00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <stdlib.h>
00010 #include <string.h>
00011 #include <assert.h>
00012 #include <iostream>
00013 #include <math.h>
00014
00015 #include "imagergba.h"
00016 #include "clip.h"
00017
00018 #include <tiff.h>
00019 #include <tiffio.h>
00020
00021 #define HAVE_BIGENDIAN (*(unsigned short *)"12" == 0x3132)
00022
00023 #define SWAP_UINT32(x) (( ((unsigned long)(x) << 24) | ((((unsigned long)(x)) & 0x0000ff00UL) << 8) | ((((unsigned long)(x)) & 0x00ff0000UL) >> 8) | ( ((unsigned long)(x)) >> 24)))
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00042
00043 ImageRGBA *imageRgbaNew(int width, int height)
00051 {
00052 ImageRGBA *result = NULL;
00053
00054 assert(width >= 0);
00055 assert(height >= 0);
00056
00057 result = (ImageRGBA *)malloc(sizeof(ImageRGBA));
00058 result->width = width;
00059 result->height = height;
00060 result->bytesPerPixel = 4;
00061 result->data = (Rgba *)malloc(width * height * sizeof(Rgba));
00062
00063 return result;
00064 }
00065
00066 void imageRgbaFree(ImageRGBA *img)
00073 {
00074 assert(img->bytesPerPixel == sizeof(Rgba));
00075 delete img->data;
00076 delete img;
00077 }
00078
00079
00080
00081 ImageRGBA *imageRgbaClone(const ImageRGBA *img)
00088 {
00089 assert(img->bytesPerPixel == sizeof(Rgba));
00090
00091 ImageRGBA *result = imageRgbaNew(img->width, img->height);
00092
00093 if (result)
00094 memcpy(result->data, img->data, img->width * img->height * sizeof(Rgba));
00095
00096 return result;
00097 }
00098
00099
00100
00101
00102 void imageRgbaCopy(const ImageRGBA *src, const ImageRGBA *dest)
00109 {
00110 assert(src->height == dest->height && src->width == dest->width);
00111
00112 memcpy(dest->data, src->data, src->width * src->height * sizeof(Rgba));
00113
00114 }
00115
00117
00118 void imageRgbaClear(ImageRGBA *img)
00125 {
00126 assert(img->bytesPerPixel == sizeof(Rgba));
00127 imageRgbaSet(img, 255, 255, 255, 255);
00128 }
00129
00130 void imageRgbaSet(ImageRGBA *img,
00131 unsigned r, unsigned g, unsigned b, unsigned a)
00136 {
00137 assert(img->bytesPerPixel == sizeof(Rgba));
00138
00139 Rgba val = {r, g, b, a};
00140 Rgba *p, *e = img->data + img->width * img->height;
00141
00142 for (p=img->data; p<e; *p++=val);
00143 }
00144
00145 void imageRgbaSetArea(ImageRGBA *img, int x0, int y0, int x1, int y1, Rgba color)
00146 {
00147 for (int y = y0; y < y1; y++)
00148 {
00149 for (int x = x0; x < x1; x++)
00150 {
00151 img->data[x + img->width * y] = color;
00152 }
00153 }
00154 }
00155
00157
00158 ImageRGBA *imageRgbaReadTIFF(const char *fname)
00167 {
00168 TIFF *tif;
00169 if ((tif = TIFFOpen(fname, "r")) != NULL)
00170 {
00171 ImageRGBA *result = NULL;
00172 uint32 width, height;
00173
00174 TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
00175 TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
00176
00177 if ((result = imageRgbaNew(width, height)) != NULL)
00178 {
00179 if (TIFFReadRGBAImage(tif, result->width, result->height, (uint32 *)result->data, 0))
00180 {
00181
00182
00183 unsigned long *p, *q, temp;
00184 int c;
00185
00186 if (HAVE_BIGENDIAN)
00187 {
00188 for (p=(unsigned long *)result->data,
00189 q=(unsigned long *)result->data+(result->height-1)*result->width;
00190 p < q;
00191 p+=result->width, q-=result->width)
00192 for (c=result->width-1; c>=0; c--)
00193 {
00194 temp=p[c];
00195 p[c]=SWAP_UINT32(q[c]);
00196 q[c]=SWAP_UINT32(temp);
00197 }
00198
00199 if (p == q)
00200 for (c=result->width-1; c>=0; c--)
00201 { p[c]=SWAP_UINT32(p[c]); }
00202 }
00203 else
00204 {
00205 unsigned long *p, *q, temp;
00206 int c;
00207 for (p=(unsigned long *)result->data,
00208 q=(unsigned long *)result->data+(result->height-1)*result->width;
00209 p < q;
00210 p+=result->width, q-=result->width)
00211 for (c=result->width-1; c>=0; c--)
00212 {
00213 temp=p[c];
00214 p[c]=q[c];
00215 q[c]=temp;
00216 }
00217 }
00218 }
00219 else
00220 {
00221 imageRgbaFree(result);
00222
00223 result = NULL;
00224 }
00225 }
00226
00227 TIFFClose(tif);
00228 return result;
00229 }
00230
00231 return NULL;
00232 }
00233
00234 int imageRgbaWriteTIFF(const char *fname, const ImageRGBA *img)
00244 {
00245 assert(img->bytesPerPixel == sizeof(Rgba));
00246
00247 TIFF *tif;
00248 if ((tif = TIFFOpen(fname, "w")) != NULL)
00249 {
00250 int y;
00251
00252 TIFFSetField(tif, TIFFTAG_SUBFILETYPE, 0);
00253 TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, img->width);
00254 TIFFSetField(tif, TIFFTAG_IMAGELENGTH, img->height);
00255 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 4);
00256 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8, 8, 8, 8);
00257 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS);
00258 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
00259 TIFFSetField(tif, TIFFTAG_DOCUMENTNAME, fname);
00260 TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, "Created With My Personal Painter Application :-)");
00261 TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
00262 TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 64);
00263 TIFFSetField(tif, TIFFTAG_XRESOLUTION, 75.0);
00264 TIFFSetField(tif, TIFFTAG_YRESOLUTION, 75.0);
00265 TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
00266 TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
00267
00268 for (y=0; y<img->height; y++)
00269 if (TIFFWriteScanline(tif, img->data+y*img->width, y, 0) < 0)
00270 break;
00271
00272 if (y < img->height)
00273 {
00274
00275 TIFFClose(tif);
00276 return 1;
00277 }
00278 else
00279 {
00280 TIFFClose(tif);
00281 return 0;
00282 }
00283 }
00284 else
00285
00286
00287 return 1;
00288 }
00289
00291
00292 void imageRgbaDrawLine (ImageRGBA *img, int x0, int y0, int x1, int y1, Rgba colorValue, int lx0, int ly0, int lx1, int ly1)
00293 {
00294 if (lx1 == -1)
00295 lx1 = img->width;
00296 if (ly1 == -1)
00297 ly1 = img->height;
00298
00299
00300 {
00301 float x[2] = {(float)x0, (float)x1};
00302 float y[2] = {(float)y0, (float)y1};
00303
00304 if (clip(x, y, 0, 0, (float)img->width-1, (float)img->height-1) == 2)
00305 return;
00306
00307 x0 = (int)floor(x[0] + 0.5);
00308 y0 = (int)floor(y[0] + 0.5);
00309 x1 = (int)floor(x[1] + 0.5);
00310 y1 = (int)floor(y[1] + 0.5);
00311 }
00312
00313
00314 int x = x0, y = y0;
00315
00316
00317 int dx = x1-x0, dy = y1-y0;
00318
00319
00320 int sx = (dx > 0 ? 1 : (dx < 0 ? -1 : 0));
00321 int sy = (dy > 0 ? 1 : (dy < 0 ? -1 : 0));
00322
00323
00324 if ( dx < 0 ) dx = -dx;
00325 if ( dy < 0 ) dy = -dy;
00326 int ax = 2*dx, ay = 2*dy;
00327 int decx, decy;
00328
00329
00330 int max = dx, var = 0;
00331 if ( dy > max ) { var = 1; }
00332
00333
00334 switch ( var )
00335 {
00336 case 0:
00337 for (decy=ay-dx; ; x += sx, decy += ay)
00338 {
00339
00340 if (x >= lx0 && x <= lx1 && y >= ly0 && y <= ly1)
00341 img->data[x + y*img->width] = colorValue;
00342
00343
00344 if ( x == x1 ) break;
00345 if ( decy >= 0 ) { decy -= ax; y += sy; }
00346 }
00347 break;
00348 case 1:
00349 for (decx=ax-dy; ; y += sy, decx += ax)
00350 {
00351
00352 if (x >= lx0 && x <= lx1 && y >= ly0 && y <= ly1)
00353 img->data[x + y*img->width] = colorValue;
00354
00355
00356 if ( y == y1 ) break;
00357 if ( decx >= 0 ) { decx -= ay; x += sx; }
00358 }
00359 break;
00360 }
00361 }
00362
00364
00365 void imageRgbaInvertLine(ImageRGBA *img, int x0, int y0, int x1, int y1, int lx0, int ly0, int lx1, int ly1)
00366 {
00367 if (lx1 == -1)
00368 lx1 = img->width;
00369 if (ly1 == -1)
00370 ly1 = img->height;
00371
00372
00373 {
00374 float x[2] = {(float)x0, (float)x1};
00375 float y[2] = {(float)y0, (float)y1};
00376
00377 if (clip(x, y, 0.0f, 0.0f, (float)(img->width-1), (float)(img->height-1)) == 2)
00378 return;
00379
00380 x0 = (int)floor(x[0] + 0.5);
00381 y0 = (int)floor(y[0] + 0.5);
00382 x1 = (int)floor(x[1] + 0.5);
00383 y1 = (int)floor(y[1] + 0.5);
00384 }
00385
00386
00387 int x = x0, y = y0;
00388
00389
00390 int dx = x1-x0, dy = y1-y0;
00391
00392
00393 int sx = (dx > 0 ? 1 : (dx < 0 ? -1 : 0));
00394 int sy = (dy > 0 ? 1 : (dy < 0 ? -1 : 0));
00395
00396
00397 if ( dx < 0 ) dx = -dx;
00398 if ( dy < 0 ) dy = -dy;
00399 int ax = 2*dx, ay = 2*dy;
00400 int decx, decy;
00401
00402
00403 int max = dx, var = 0;
00404 if ( dy > max ) { var = 1; }
00405
00406
00407 switch ( var )
00408 {
00409 case 0:
00410 for (decy=ay-dx; ; x += sx, decy += ay)
00411 {
00412
00413 if (x >= lx0 && x <= lx1 && y >= ly0 && y <= ly1)
00414 {
00415 img->data[x + y*img->width].r = 255 - img->data[x + y*img->width].r;
00416 img->data[x + y*img->width].g = 255 - img->data[x + y*img->width].g;
00417 img->data[x + y*img->width].b = 255 - img->data[x + y*img->width].b;
00418 }
00419
00420
00421 if ( x == x1 ) break;
00422 if ( decy >= 0 ) { decy -= ax; y += sy; }
00423 }
00424 break;
00425 case 1:
00426 for (decx=ax-dy; ; y += sy, decx += ax)
00427 {
00428
00429 if (x >= lx0 && x <= lx1 && y >= ly0 && y <= ly1)
00430 {
00431 img->data[x + y*img->width].r = 255 - img->data[x + y*img->width].r;
00432 img->data[x + y*img->width].g = 255 - img->data[x + y*img->width].g;
00433 img->data[x + y*img->width].b = 255 - img->data[x + y*img->width].b;
00434 }
00435
00436
00437 if ( y == y1 ) break;
00438 if ( decx >= 0 ) { decx -= ay; x += sx; }
00439 }
00440 break;
00441 }
00442 }
00443
00445
00446 void imageRgbaDrawHorizontalAreaLine(ImageRGBA *img, int x0, int x1, int y, int colorOffset)
00447 {
00448 char color;
00449 int location;
00450 for (int x = x1; x >= x0; x--)
00451 {
00452 if ((colorOffset % 8) < 4)
00453 color = 0;
00454 else
00455 color = 255;
00456
00457 location = x + img->width * y;
00458 img->data[location].r = color;
00459 img->data[location].g = color;
00460 img->data[location].b = color;
00461 img->data[location].a = 255;
00462 colorOffset++;
00463 }
00464 }
00465
00466 void imageRgbaDrawVerticalAreaLine(ImageRGBA *img, int y0, int y1, int x, int colorOffset)
00467 {
00468 char color;
00469 int location;
00470 for (int y = y1; y >= y0; y--)
00471 {
00472 if ((colorOffset % 8) < 4)
00473 color = 0;
00474 else
00475 color = 255;
00476
00477 location = x + img->width * y;
00478 img->data[location].r = color;
00479 img->data[location].g = color;
00480 img->data[location].b = color;
00481 img->data[location].a = 255;
00482 colorOffset++;
00483 }
00484 }
00485
00487
00488
00489 void imageRgbaDrawEllipse(ImageRGBA *img, int cx, int cy, int halfaxis_x, int halfaxis_y, Rgba colorValue, int lx0, int ly0, int lx1, int ly1)
00490 {
00491 if (lx1 == -1)
00492 lx1 = img->width;
00493 if (ly1 == -1)
00494 ly1 = img->height;
00495
00496 halfaxis_x = abs(halfaxis_x);
00497
00498
00499 long t1 = halfaxis_x*halfaxis_x, t2 = t1<<1, t3 = t2<<1;
00500 long t4 = halfaxis_y*halfaxis_y, t5 = t4<<1, t6 = t5<<1;
00501 long t7 = halfaxis_x*t5, t8 = t7<<1, t9 = 0L;
00502 long d1 = t2 - t7 + (t4>>1);
00503 long d2 = (t1>>1) - t8 + t5;
00504
00505 int x = halfaxis_x, y = 0;
00506
00507 while (d2 < 0)
00508 {
00509
00510 if ((cx + x) >= lx0 && (cx + x) <= lx1 && (cy + y) >= ly0 && (cy + y) <= ly1)
00511 imageRgbaDrawPoint(img, cx + x, cy + y, colorValue);
00512 if ((cx + x) >= lx0 && (cx + x) <= lx1 && (cy - y) >= ly0 && (cy - y) <= ly1)
00513 imageRgbaDrawPoint(img, cx + x, cy - y, colorValue);
00514 if ((cx - x) >= lx0 && (cx - x) <= lx1 && (cy + y) >= ly0 && (cy + y) <= ly1)
00515 imageRgbaDrawPoint(img, cx - x, cy + y, colorValue);
00516 if ((cx - x) >= lx0 && (cx - x) <= lx1 && (cy - y) >= ly0 && (cy - y) <= ly1)
00517 imageRgbaDrawPoint(img, cx - x, cy - y, colorValue);
00518
00519 y++;
00520 t9 += t3;
00521 if (d1 < 0)
00522 {
00523 d1 += t9 + t2;
00524 d2 += t9;
00525 }
00526 else
00527 {
00528 x--;
00529 t8 -= t6;
00530 d1 += t9 + t2 - t8;
00531 d2 += t9 + t5 - t8;
00532 }
00533 }
00534
00535 while (x >= 0)
00536 {
00537
00538 if ((cx + x) >= lx0 && (cx + x) <= lx1 && (cy + y) >= ly0 && (cy + y) <= ly1)
00539 imageRgbaDrawPoint(img, cx + x, cy + y, colorValue);
00540 if ((cx + x) >= lx0 && (cx + x) <= lx1 && (cy - y) >= ly0 && (cy - y) <= ly1)
00541 imageRgbaDrawPoint(img, cx + x, cy - y, colorValue);
00542 if ((cx - x) >= lx0 && (cx - x) <= lx1 && (cy + y) >= ly0 && (cy + y) <= ly1)
00543 imageRgbaDrawPoint(img, cx - x, cy + y, colorValue);
00544 if ((cx - x) >= lx0 && (cx - x) <= lx1 && (cy - y) >= ly0 && (cy - y) <= ly1)
00545 imageRgbaDrawPoint(img, cx - x, cy - y, colorValue);
00546
00547 x--;
00548 t8 -= t6;
00549 if (d2 < 0)
00550 {
00551 y++;
00552 t9 += t3;
00553 d2 += t9 + t5 - t8;
00554 }
00555 else
00556 d2 += t5 - t8;
00557 }
00558 }
00559
00561
00562
00563 void imageRgbaInvertEllipse(ImageRGBA *img, int cx, int cy, int halfaxis_x, int halfaxis_y)
00564 {
00565 halfaxis_x = abs(halfaxis_x);
00566
00567
00568 long t1 = halfaxis_x*halfaxis_x, t2 = t1<<1, t3 = t2<<1;
00569 long t4 = halfaxis_y*halfaxis_y, t5 = t4<<1, t6 = t5<<1;
00570 long t7 = halfaxis_x*t5, t8 = t7<<1, t9 = 0L;
00571 long d1 = t2 - t7 + (t4>>1);
00572 long d2 = (t1>>1) - t8 + t5;
00573
00574 int x = halfaxis_x, y = 0;
00575
00576 while (d2 < 0)
00577 {
00578
00579 imageRgbaDrawInvertedPoint(img, cx + x, cy + y);
00580 imageRgbaDrawInvertedPoint(img, cx + x, cy - y);
00581 imageRgbaDrawInvertedPoint(img, cx - x, cy + y);
00582 imageRgbaDrawInvertedPoint(img, cx - x, cy - y);
00583
00584 y++;
00585 t9 += t3;
00586 if (d1 < 0)
00587 {
00588 d1 += t9 + t2;
00589 d2 += t9;
00590 }
00591 else
00592 {
00593 x--;
00594 t8 -= t6;
00595 d1 += t9 + t2 - t8;
00596 d2 += t9 + t5 - t8;
00597 }
00598 }
00599
00600 while (x >= 0)
00601 {
00602
00603 imageRgbaDrawInvertedPoint(img, cx + x, cy + y);
00604 imageRgbaDrawInvertedPoint(img, cx + x, cy - y);
00605 imageRgbaDrawInvertedPoint(img, cx - x, cy + y);
00606 imageRgbaDrawInvertedPoint(img, cx - x, cy - y);
00607
00608 x--;
00609 t8 -= t6;
00610 if (d2 < 0)
00611 {
00612 y++;
00613 t9 += t3;
00614 d2 += t9 + t5 - t8;
00615 }
00616 else
00617 d2 += t5 - t8;
00618 }
00619 }
00620
00622
00623 inline void imageRgbaDrawPoint(ImageRGBA *img, int x, int y, Rgba colorValue)
00624 {
00625
00626 if (x >= 0 && y >= 0 && x < img->width && y < img->height) {
00627 img->data[x + y*img->width] = colorValue;
00628 }
00629 }
00630
00632
00633 inline void imageRgbaDrawInvertedPoint(ImageRGBA *img, int x, int y)
00634 {
00635
00636 if (x >= 0 && y >= 0 && x < img->width && y < img->height) {
00637 img->data[x + y*img->width].r = 255 - img->data[x + y*img->width].r;
00638 img->data[x + y*img->width].g = 255 - img->data[x + y*img->width].g;
00639 img->data[x + y*img->width].b = 255 - img->data[x + y*img->width].b;
00640 }
00641 }
00642
00644
00646
00647 Rgba imageRgbaInterpolate(ImageRGBA *img, float x, float y)
00648 {
00649 const int w = img->width;
00650 const int h = img->height;
00651 int ix, iy, iix, iiy;
00652 float fx, fy, dfx, dfy;
00653
00654 if (x < 0)
00655 x = 0;
00656 if (y < 0)
00657 y = 0;
00658 if (y > (h-1))
00659 y = h-1;
00660 if (x > (w-1))
00661 x = w-1;
00662
00663 ix = int(x);
00664 iy = int(y);
00665
00666 iix = ix + 1;
00667 iiy = iy + 1;
00668 if (iix > (w-1))
00669 iix = 0;
00670 if (iiy > (h-1))
00671 iiy = 0;
00672
00673 fx = x - ix;
00674 fy = y - iy;
00675 dfx = 1 - fx;
00676 dfy = 1 - fy;
00677
00678 Rgba interpolated;
00679 Rgba top, bottom;
00680 Rgba topleft, topright, bottomleft, bottomright;
00681
00682 topleft = img->data[ix + w*iy];
00683 topright = img->data[iix + w*iy];
00684 bottomleft = img->data[ix + w*iiy];
00685 bottomright = img->data[iix + w*iiy];
00686
00687 top.r = int(dfx*topleft.r + fx*topright.r);
00688 top.g = int(dfx*topleft.g + fx*topright.g);
00689 top.b = int(dfx*topleft.b + fx*topright.b);
00690
00691
00692 bottom.r = int(dfx*bottomleft.r + fx*bottomright.r);
00693 bottom.g = int(dfx*bottomleft.g + fx*bottomright.g);
00694 bottom.b = int(dfx*bottomleft.b + fx*bottomright.b);
00695
00696
00697 interpolated.r = int(dfy*top.r + fy*bottom.r);
00698 interpolated.g = int(dfy*top.g + fy*bottom.g);
00699 interpolated.b = int(dfy*top.b + fy*bottom.b);
00700
00701 interpolated.a = 255;
00702
00703 return interpolated;
00704 }
00705
00706 int imageRgbaInterpolateSubImage(ImageRGBA *img, float x, float y, int w, int h, int offset)
00707 {
00708 int ix, iy, iix, iiy;
00709 float fx, fy, dfx, dfy;
00710
00711 ix = int(x);
00712 iy = int(y);
00713
00714 if (ix < 0)
00715 {
00716 ix += w;
00717 x += w;
00718 }
00719 if (iy < 0)
00720 {
00721 iy += h;
00722 y += h;
00723 }
00724 if (ix > (w-1))
00725 {
00726 ix -= w;
00727 x -= w;
00728 }
00729 if (iy > (h-1))
00730 {
00731 iy -= h;
00732 y -= h;
00733 }
00734
00735
00736 fx = x - ix;
00737 fy = y - iy;
00738 dfx = 1 - fx;
00739 dfy = 1 - fy;
00740
00741 iix = ix + 1;
00742 iiy = iy + 1;
00743 if (iix > (w-1))
00744 iix -= w;
00745 if (iiy > (h-1))
00746 iiy -= h;
00747
00748
00749 int interpolated;
00750 int top, bottom;
00751 int topleft, topright, bottomleft, bottomright;
00752
00753 topleft = img->data[offset + ix + w*iy].r;
00754 topright = img->data[offset + iix + w*iy].r;
00755 bottomleft = img->data[offset + ix + w*iiy].r;
00756 bottomright = img->data[offset + iix + w*iiy].r;
00757
00758 top = int(dfx*topleft + fx*topright);
00759 bottom = int(dfx*bottomleft + fx*bottomright);
00760
00761 interpolated = int(dfy*top + fy*bottom);
00762
00763 return interpolated;
00764 }
00765
00766 Rgba imageRgbaInterpolateColors(float x, float y, Rgba topleft, Rgba topright, Rgba bottomleft, Rgba bottomright)
00767 {
00768 int ix, iy;
00769 float fx, fy, dfx, dfy;
00770
00771 ix = int(x);
00772 iy = int(y);
00773 fx = x - ix;
00774 fy = y - iy;
00775 dfx = 1 - fx;
00776 dfy = 1 - fy;
00777
00778 Rgba interpolated;
00779 Rgba top, bottom;
00780
00781 top.r = int(dfx*topleft.r + fx*topright.r);
00782 top.g = int(dfx*topleft.g + fx*topright.g);
00783 top.b = int(dfx*topleft.b + fx*topright.b);
00784
00785
00786 bottom.r = int(dfx*bottomleft.r + fx*bottomright.r);
00787 bottom.g = int(dfx*bottomleft.g + fx*bottomright.g);
00788 bottom.b = int(dfx*bottomleft.b + fx*bottomright.b);
00789
00790
00791 interpolated.r = int(dfy*top.r + fy*bottom.r);
00792 interpolated.g = int(dfy*top.g + fy*bottom.g);
00793 interpolated.b = int(dfy*top.b + fy*bottom.b);
00794
00795 interpolated.a = 255;
00796
00797 return interpolated;
00798 }
00799
00800
00802
00803
00805
00806 Hsva RGBtoHSV(Rgba RGBColor)
00807 {
00808
00809
00810
00811
00812
00813 float R, G, B, MAX, MIN;
00814 Hsva HSVColor;
00815
00816 R = RGBColor.r / 255.0;
00817 G = RGBColor.g / 255.0;
00818 B = RGBColor.b / 255.0;
00819
00820 MAX = R;
00821 if (G > MAX)
00822 MAX = G;
00823 if (B > MAX)
00824 MAX = B;
00825
00826 MIN = R;
00827 if (G < MIN)
00828 MIN = G;
00829 if (B < MIN)
00830 MIN = B;
00831
00832
00833 if (MAX != MIN)
00834 {
00835 if (MAX == R)
00836 HSVColor.h = (0.0 + (G - B) / (MAX - MIN)) * 60.0;
00837 if (MAX == G)
00838 HSVColor.h = (2.0 + (B - R) / (MAX - MIN)) * 60.0;
00839 if (MAX == B)
00840 HSVColor.h = (4.0 + (R - G) / (MAX - MIN)) * 60.0;
00841 }
00842
00843 if (MAX > 0)
00844 HSVColor.s = (MAX - MIN) / MAX;
00845
00846 HSVColor.v = MAX;
00847
00848 HSVColor.a = RGBColor.a;
00849 return HSVColor;
00850 }
00851
00852 Rgba HSVtoRGB(Hsva HSVColor)
00853 {
00854
00855
00856 float Hi, f, p, q, t;
00857 Rgba RGBColor;
00858
00859
00860 Hi = int(fmod(HSVColor.h / 60.0, 6));
00861 f = (HSVColor.h / 60.0) - Hi;
00862 p = HSVColor.v * (1.0 - HSVColor.s);
00863 q = HSVColor.v * (1.0 - (HSVColor.s * f));
00864 t = HSVColor.v * (1.0 - (HSVColor.s * (1.0 - f)));
00865
00866 if (Hi == 0)
00867 {
00868 RGBColor.r = int(HSVColor.v * 255);
00869 RGBColor.g = int(t * 255);
00870 RGBColor.b = int(p * 255);
00871 }
00872 else if (Hi == 1)
00873 {
00874 RGBColor.r = int(q * 255);
00875 RGBColor.g = int(HSVColor.v * 255);
00876 RGBColor.b = int(p * 255);
00877 }
00878 else if (Hi == 2)
00879 {
00880 RGBColor.r = int(p * 255);
00881 RGBColor.g = int(HSVColor.v * 255);
00882 RGBColor.b = int(t * 255);
00883 }
00884 else if (Hi == 3)
00885 {
00886 RGBColor.r = int(p * 255);
00887 RGBColor.g = int(q * 255);
00888 RGBColor.b = int(HSVColor.v * 255);
00889 }
00890 else if (Hi == 4)
00891 {
00892 RGBColor.r = int(t * 255);
00893 RGBColor.g = int(p * 255);
00894 RGBColor.b = int(HSVColor.v * 255);
00895 }
00896 else if (Hi == 5)
00897 {
00898 RGBColor.r = int(HSVColor.v * 255);
00899 RGBColor.g = int(p * 255);
00900 RGBColor.b = int(q * 255);
00901 }
00902
00903 RGBColor.a = HSVColor.a;
00904 return RGBColor;
00905 }
00906
00908
00910
00911 {
00912 int loops = 1;
00913 float oldValue1 = value1;
00914 ImageRGBA *swap;
00915
00916 if (mode == 2)
00917 loops = int(oldValue1);
00918 for (int l = 0; l < loops; l++)
00919 {
00920 if (l > 0)
00921 value1 = int(exp((l*-l)/oldValue1) * oldValue1);
00922
00923 if (value1 > 0)
00924 {
00925 horizontal_blur(img, temp2, lowAreaX, lowAreaY, highAreaX, highAreaY, value1, mode, calc);
00926
00927 swap = img;
00928 img = temp2;
00929 temp2 = swap;
00930
00931 vertical_blur(img, temp2, lowAreaX, lowAreaY, highAreaX, highAreaY, value1, mode, calc);
00932 }
00933 swap = img;
00934 img = temp2;
00935 temp2 = swap;
00936 }
00937 }
00938
00939 void horizontal_blur(ImageRGBA *img, ImageRGBA *temp2, int lowAreaX, int lowAreaY, int highAreaX, int highAreaY, float value1, int mode, unsigned char calc)
00940 {
00941 int mx, location, count = 0;
00942 int R = 0, G = 0, B = 0, A = 0;
00943
00944 for (int _y = lowAreaY; _y <= highAreaY; _y++)
00945 {
00946 for (int _x = lowAreaX; _x <= highAreaX; _x++)
00947 {
00948 if (_x == lowAreaX)
00949 {
00950 R = 0;
00951 G = 0;
00952 B = 0;
00953 A = 0;
00954 count = 0;
00955 for (int x = 0; x <= int(value1); x++)
00956 {
00957 mx = _x + x;
00958
00959 if (mx < lowAreaX) { mx = lowAreaX; }
00960 if (mx > highAreaX)
00961 break;
00962
00963 if (_y > highAreaY)
00964 break;
00965 if (!(_y < lowAreaY))
00966 {
00967
00968 count++;
00969 location = mx + img->width * _y;
00970
00971 R += temp2->data[location].r;
00972 G += temp2->data[location].g;
00973 B += temp2->data[location].b;
00974 A += temp2->data[location].a;
00975 }
00976 }
00977 }
00978 else
00979 {
00980 if ((_x - int(value1)) > lowAreaX)
00981 {
00982 if (_y > highAreaY)
00983 break;
00984 if (!(_y < lowAreaY))
00985 {
00986 count--;
00987 location = (_x - int(value1) - 1) + img->width * _y;
00988
00989 R -= temp2->data[location].r;
00990 G -= temp2->data[location].g;
00991 B -= temp2->data[location].b;
00992 A -= temp2->data[location].a;
00993 }
00994 }
00995 if ((_x + int(value1)) <= highAreaX)
00996 {
00997 if (_y > highAreaY)
00998 break;
00999 if (!(_y < lowAreaY))
01000 {
01001 count++;
01002 location = (_x + int(value1)) + img->width * _y;
01003
01004 R += temp2->data[location].r;
01005 G += temp2->data[location].g;
01006 B += temp2->data[location].b;
01007 A += temp2->data[location].a;
01008 }
01009 }
01010 }
01011 if (count != 0)
01012 {
01013 int location = _x + img->width * _y;
01014 int _R = (R / count);
01015 int _G = (G / count);
01016 int _B = (B / count);
01017 int _A = (A / count);
01018 if (calc == 2)
01019 {
01020 _R = int(((float)_A / 255 * _R) + ((float)img->data[location].a / 255 * img->data[location].r));
01021 _G = int(((float)_A / 255 * _G) + ((float)img->data[location].a / 255 * img->data[location].g));
01022 _B = int(((float)_A / 255 * _B) + ((float)img->data[location].a / 255 * img->data[location].b));
01023 _A = _A + img->data[location].a;
01024 _R = int((float)_R / ((float)_A / 255));
01025 _G = int((float)_G / ((float)_A / 255));
01026 _B = int((float)_B / ((float)_A / 255));
01027 _A = int((float)_A);
01028 }
01029
01030 if (_R < 0) { _R = 0; }
01031 if (_G < 0) { _G = 0; }
01032 if (_B < 0) { _B = 0; }
01033 if (_A < 0) { _A = 0; }
01034 if (_R > 255) { _R = 255; }
01035 if (_G > 255) { _G = 255; }
01036 if (_B > 255) { _B = 255; }
01037 if (_A > 255) { _A = 255; }
01038 img->data[location] = (Rgba){_R, _G, _B, _A};
01039 }
01040 }
01041 }
01042 }
01043
01044 void vertical_blur(ImageRGBA *img, ImageRGBA *temp2, int lowAreaX, int lowAreaY, int highAreaX, int highAreaY, float value1, int mode, unsigned char calc)
01045 {
01046 int my, location, count = 0;
01047 int R = 0, G = 0, B = 0, A = 0;
01048
01049 for (int _x = lowAreaX; _x <= highAreaX; _x++)
01050 {
01051 for (int _y = lowAreaY; _y <= highAreaY; _y++)
01052 {
01053 if (_y == lowAreaY)
01054 {
01055 R = 0;
01056 G = 0;
01057 B = 0;
01058 A = 0;
01059 count = 0;
01060 for (int y = 0; y <= int(value1); y++)
01061 {
01062 my = _y + y;
01063
01064 if (my < lowAreaY) { my = lowAreaY; }
01065 if (my > highAreaY)
01066 break;
01067
01068 if (_x > highAreaX)
01069 break;
01070 if (!(_x < lowAreaX))
01071 {
01072
01073 count++;
01074 location = _x + img->width * my;
01075
01076 R += temp2->data[location].r;
01077 G += temp2->data[location].g;
01078 B += temp2->data[location].b;
01079 A += temp2->data[location].a;
01080 }
01081 }
01082 }
01083 else
01084 {
01085 if ((_y - int(value1)) > lowAreaY)
01086 {
01087 if (_x > highAreaX)
01088 break;
01089 if (!(_x < lowAreaX))
01090 {
01091 count--;
01092 location = _x + img->width * (_y - int(value1) - 1);
01093
01094 R -= temp2->data[location].r;
01095 G -= temp2->data[location].g;
01096 B -= temp2->data[location].b;
01097 A -= temp2->data[location].a;
01098 }
01099 }
01100 if ((_y + int(value1)) <= highAreaY)
01101 {
01102 if (_x > highAreaX)
01103 break;
01104 if (!(_x < lowAreaX))
01105 {
01106 count++;
01107 location = _x + img->width * (_y + int(value1));
01108
01109 R += temp2->data[location].r;
01110 G += temp2->data[location].g;
01111 B += temp2->data[location].b;
01112 A += temp2->data[location].a;
01113 }
01114 }
01115 }
01116 if (count != 0)
01117 {
01118 int location = _x + img->width * _y;
01119 int _R = (R / count);
01120 int _G = (G / count);
01121 int _B = (B / count);
01122 int _A = (A / count);
01123 if (calc == 2)
01124 {
01125 _R = int(((float)_A / 255 * _R) + ((float)img->data[location].a / 255 * img->data[location].r));
01126 _G = int(((float)_A / 255 * _G) + ((float)img->data[location].a / 255 * img->data[location].g));
01127 _B = int(((float)_A / 255 * _B) + ((float)img->data[location].a / 255 * img->data[location].b));
01128 _A = _A + img->data[location].a;
01129 _R = int((float)_R / ((float)_A / 255));
01130 _G = int((float)_G / ((float)_A / 255));
01131 _B = int((float)_B / ((float)_A / 255));
01132 _A = int((float)_A);
01133 }
01134
01135 if (_R < 0) { _R = 0; }
01136 if (_G < 0) { _G = 0; }
01137 if (_B < 0) { _B = 0; }
01138 if (_A < 0) { _A = 0; }
01139 if (_R > 255) { _R = 255; }
01140 if (_G > 255) { _G = 255; }
01141 if (_B > 255) { _B = 255; }
01142 if (_A > 255) { _A = 255; }
01143 img->data[location] = (Rgba){_R, _G, _B, _A};
01144 }
01145 }
01146 }
01147 }
01148
01149 void motion_blur(ImageRGBA *img, ImageRGBA *temp2, int lowAreaX, int lowAreaY, int highAreaX, int highAreaY, float value1, float value2, int mode, unsigned char calc)
01150 {
01151 int maxdist, maxdistX, maxdistY;
01152 int newX, newY, maxY, location;
01153 int oldX, oldY;
01154 int R = 0, G = 0, B = 0, A = 0, count = 0;
01155 float angle = value2 * M_PI / 180 - M_PI / 2;
01156
01157
01158 for (int x = lowAreaX - 1; x <= highAreaX + 1; x++)
01159 {
01160 if (x == lowAreaX - 1 && angle < 0)
01161 maxY = highAreaY + 1;
01162 else if (x == highAreaX + 1 && angle > 0)
01163 maxY = highAreaY + 1;
01164 else
01165 maxY = lowAreaY - 1;
01166
01167 for (int y = lowAreaY - 1; y <= maxY; y++)
01168 {
01169 R = 0;
01170 G = 0;
01171 B = 0;
01172 A = 0;
01173 count = 0;
01174 if (angle < 0)
01175 maxdistX = (highAreaX - x + 10);
01176 else if (angle > 0)
01177 maxdistX = x + 10;
01178 else
01179 maxdistX = highAreaX + 10;
01180 if (maxdistX > (highAreaX + 10))
01181 maxdistX = highAreaX + 10;
01182 else if (maxdist < (-(highAreaX + 10)))
01183 maxdist = -(highAreaX + 10);
01184 maxdistY = int(maxdistX / tan(angle)+10);
01185 if (maxdistY > (highAreaY + 10))
01186 maxdistY = highAreaY + 10;
01187 else if (maxdistY < (-(highAreaY + 10)))
01188 maxdistY = -(highAreaY + 10);
01189 maxdist = int(sqrt(maxdistX*maxdistX + maxdistY*maxdistY)+1);
01190 for (int dist = int(-value1); dist < maxdist; dist++)
01191 {
01192
01193 if ((dist - value1) >= 0)
01194 {
01195 newX = int(x - sin(angle)*(dist-value1));
01196 newY = int(y + cos(angle)*(dist-value1));
01197 if (newX >= lowAreaX && newX <= highAreaX && newY >= lowAreaY && newY <= highAreaY)
01198 {
01199 location = newX + img->width * newY;
01200 R -= temp2->data[location].r;
01201 G -= temp2->data[location].g;
01202 B -= temp2->data[location].b;
01203 A -= temp2->data[location].a;
01204 count--;
01205 }
01206 }
01207
01208 newX = int(x - sin(angle)*(dist+value1));
01209 newY = int(y + cos(angle)*(dist+value1));
01210 if (newX >= lowAreaX && newX <= highAreaX && newY >= lowAreaY && newY <= highAreaY)
01211 {
01212 location = newX + img->width * newY;
01213 R += temp2->data[location].r;
01214 G += temp2->data[location].g;
01215 B += temp2->data[location].b;
01216 A += temp2->data[location].a;
01217 count++;
01218 }
01219
01220 if (dist >= 0)
01221 {
01222 newX = int(x - sin(angle)*dist);
01223 newY = int(y + cos(angle)*dist);
01224 if (oldX != newX || oldY != newY)
01225 {
01226 if (newX >= lowAreaX && newX <= highAreaX && newY >= lowAreaY && newY <= highAreaY)
01227 {
01228 location = newX + img->width * newY;
01229 if (count != 0)
01230 {
01231 int _R = (R / count);
01232 int _G = (G / count);
01233 int _B = (B / count);
01234 int _A = (A / count);
01235 if (calc == 2)
01236 {
01237 _R = int(((float)_A / 255 * _R) + ((float)img->data[location].a / 255 * img->data[location].r));
01238 _G = int(((float)_A / 255 * _G) + ((float)img->data[location].a / 255 * img->data[location].g));
01239 _B = int(((float)_A / 255 * _B) + ((float)img->data[location].a / 255 * img->data[location].b));
01240 _A = _A + img->data[location].a;
01241 _R = int((float)_R * ((float)255 / _A));
01242 _G = int((float)_G * ((float)255 / _A));
01243 _B = int((float)_B * ((float)255 / _A));
01244 _A = int((float)_A);
01245 }
01246
01247 if (_R < 0) { _R = 0; }
01248 if (_G < 0) { _G = 0; }
01249 if (_B < 0) { _B = 0; }
01250 if (_A < 0) { _A = 0; }
01251 if (_R > 255) { _R = 255; }
01252 if (_G > 255) { _G = 255; }
01253 if (_B > 255) { _B = 255; }
01254 if (_A > 255) { _A = 255; }
01255 img->data[location] = (Rgba){_R, _G, _B, _A};
01256 }
01257 }
01258 }
01259 oldX = newX;
01260 oldY = newY;
01261 }
01262 }
01263 }
01264 }
01265 }
01266
01267 void holdHighest(int *stack, int numElements, int newElement)
01268 {
01269 int hold;
01270 for (int i = 0; i < numElements; i++)
01271 {
01272 if (newElement > stack[i])
01273 {
01274 hold = stack[i];
01275 stack[i] = newElement;
01276 holdHighest(stack, numElements, hold);
01277 break;
01278 }
01279 }
01280 }