diff options
Diffstat (limited to 'DevIL/src-ILU/src/ilu_manip.cpp')
-rw-r--r-- | DevIL/src-ILU/src/ilu_manip.cpp | 1024 |
1 files changed, 1024 insertions, 0 deletions
diff --git a/DevIL/src-ILU/src/ilu_manip.cpp b/DevIL/src-ILU/src/ilu_manip.cpp new file mode 100644 index 00000000..856b8c1b --- /dev/null +++ b/DevIL/src-ILU/src/ilu_manip.cpp @@ -0,0 +1,1024 @@ + +#include "ilu_internal.h" +#include "ilu_states.h" +#include <float.h> +#include <limits.h> + + +ILboolean iluCrop2D(ILuint XOff, ILuint YOff, ILuint Width, ILuint Height) { + ILuint x, y, c, OldBps; + ILubyte *Data; + ILenum Origin; + + iluCurImage = ilGetCurImage(); + if (iluCurImage == NULL) { + ilSetError(ILU_ILLEGAL_OPERATION); + return IL_FALSE; + } + + // Uh-oh, what about 0 dimensions?! + if (Width > iluCurImage->Width || Height > iluCurImage->Height) { + ilSetError(ILU_ILLEGAL_OPERATION); + return IL_FALSE; + } + + Data = (ILubyte*)ialloc(iluCurImage->SizeOfData); + if (Data == NULL) { + return IL_FALSE; + } + + OldBps = iluCurImage->Bps; + Origin = iluCurImage->Origin; + ilCopyPixels(0, 0, 0, iluCurImage->Width, iluCurImage->Height, 1, iluCurImage->Format, iluCurImage->Type, Data); + if (!ilTexImage(Width, Height, iluCurImage->Depth, iluCurImage->Bpp, iluCurImage->Format, iluCurImage->Type, NULL)) { + free(Data); + return IL_FALSE; + } + iluCurImage->Origin = Origin; + + // @TODO: Optimize! (Especially XOff * iluCurImage->Bpp...get rid of it!) + for (y = 0; y < iluCurImage->Height; y++) { + for (x = 0; x < iluCurImage->Bps; x += iluCurImage->Bpp) { + for (c = 0; c < iluCurImage->Bpp; c++) { + iluCurImage->Data[y * iluCurImage->Bps + x + c] = + Data[(y + YOff) * OldBps + x + XOff * iluCurImage->Bpp + c]; + } + } + } + + ifree(Data); + + return IL_TRUE; +} + + +ILboolean iluCrop3D(ILuint XOff, ILuint YOff, ILuint ZOff, ILuint Width, ILuint Height, ILuint Depth) +{ + ILuint x, y, z, c, OldBps, OldPlane; + ILubyte *Data; + ILenum Origin; + + iluCurImage = ilGetCurImage(); + if (iluCurImage == NULL) { + ilSetError(ILU_ILLEGAL_OPERATION); + return IL_FALSE; + } + + // Uh-oh, what about 0 dimensions?! + if (Width > iluCurImage->Width || Height > iluCurImage->Height || Depth > iluCurImage->Depth) { + ilSetError(ILU_ILLEGAL_OPERATION); + return IL_FALSE; + } + + Data = (ILubyte*)ialloc(iluCurImage->SizeOfData); + if (Data == NULL) { + return IL_FALSE; + } + + OldBps = iluCurImage->Bps; + OldPlane = iluCurImage->SizeOfPlane; + Origin = iluCurImage->Origin; + ilCopyPixels(0, 0, 0, iluCurImage->Width, iluCurImage->Height, iluCurImage->Depth, iluCurImage->Format, iluCurImage->Type, Data); + if (!ilTexImage(Width - XOff, Height - YOff, Depth - ZOff, iluCurImage->Bpp, iluCurImage->Format, iluCurImage->Type, NULL)) { + ifree(Data); + } + iluCurImage->Origin = Origin; + + for (z = 0; z < iluCurImage->Depth; z++) { + for (y = 0; y < iluCurImage->Height; y++) { + for (x = 0; x < iluCurImage->Bps; x += iluCurImage->Bpp) { + for (c = 0; c < iluCurImage->Bpp; c++) { + iluCurImage->Data[z * iluCurImage->SizeOfPlane + y * iluCurImage->Bps + x + c] = + Data[(z + ZOff) * OldPlane + (y + YOff) * OldBps + (x + XOff) + c]; + } + } + } + } + + ifree(Data); + + return IL_TRUE; +} + + +ILboolean ILAPIENTRY iluCrop(ILuint XOff, ILuint YOff, ILuint ZOff, ILuint Width, ILuint Height, ILuint Depth) +{ + if (ZOff <= 1) + return iluCrop2D(XOff, YOff, Width, Height); + return iluCrop3D(XOff, YOff, ZOff, Width, Height, Depth); +} + + +//! Enlarges the canvas +ILboolean ILAPIENTRY iluEnlargeCanvas(ILuint Width, ILuint Height, ILuint Depth) +{ + ILubyte *Data/*, Clear[4]*/; + ILuint x, y, z, OldBps, OldH, OldD, OldPlane, AddX, AddY; + ILenum Origin; + + iluCurImage = ilGetCurImage(); + if (iluCurImage == NULL) { + ilSetError(ILU_ILLEGAL_OPERATION); + return IL_FALSE; + } + + // Uh-oh, what about 0 dimensions?! + if (Width < iluCurImage->Width || Height < iluCurImage->Height || Depth < iluCurImage->Depth) { + ilSetError(ILU_ILLEGAL_OPERATION); + return IL_FALSE; + } + + if (iluCurImage->Origin == IL_ORIGIN_LOWER_LEFT) { + switch (iluPlacement) + { + case ILU_LOWER_LEFT: + AddX = 0; + AddY = 0; + break; + case ILU_LOWER_RIGHT: + AddX = Width - iluCurImage->Width; + AddY = 0; + break; + case ILU_UPPER_LEFT: + AddX = 0; + AddY = Height - iluCurImage->Height; + break; + case ILU_UPPER_RIGHT: + AddX = Width - iluCurImage->Width; + AddY = Height - iluCurImage->Height; + break; + case ILU_CENTER: + AddX = (Width - iluCurImage->Width) >> 1; + AddY = (Height - iluCurImage->Height) >> 1; + break; + default: + ilSetError(ILU_INVALID_PARAM); + return IL_FALSE; + } + } + else { // IL_ORIGIN_UPPER_LEFT + switch (iluPlacement) + { + case ILU_LOWER_LEFT: + AddX = 0; + AddY = Height - iluCurImage->Height; + break; + case ILU_LOWER_RIGHT: + AddX = Width - iluCurImage->Width; + AddY = Height - iluCurImage->Height; + break; + case ILU_UPPER_LEFT: + AddX = 0; + AddY = 0; + break; + case ILU_UPPER_RIGHT: + AddX = Width - iluCurImage->Width; + AddY = 0; + break; + case ILU_CENTER: + AddX = (Width - iluCurImage->Width) >> 1; + AddY = (Height - iluCurImage->Height) >> 1; + break; + default: + ilSetError(ILU_INVALID_PARAM); + return IL_FALSE; + } + } + + AddX *= iluCurImage->Bpp; + + Data = (ILubyte*)ialloc(iluCurImage->SizeOfData); + if (Data == NULL) { + return IL_FALSE; + } + + // Preserve old data. + OldPlane = iluCurImage->SizeOfPlane; + OldBps = iluCurImage->Bps; + OldH = iluCurImage->Height; + OldD = iluCurImage->Depth; + Origin = iluCurImage->Origin; + ilCopyPixels(0, 0, 0, iluCurImage->Width, iluCurImage->Height, OldD, iluCurImage->Format, iluCurImage->Type, Data); + + ilTexImage(Width, Height, Depth, iluCurImage->Bpp, iluCurImage->Format, iluCurImage->Type, NULL); + iluCurImage->Origin = Origin; + + ilClearImage(); + /*ilGetClear(Clear); + if (iluCurImage->Bpp == 1) { + memset(iluCurImage->Data, Clear[3], iluCurImage->SizeOfData); + } + else { + for (x = 0; x < iluCurImage->SizeOfData; x += iluCurImage->Bpp) { + for (y = 0; y < iluCurImage->Bpp; y++) { + iluCurImage->Data[y] = Clear[y]; + } + } + }*/ + + for (z = 0; z < OldD; z++) { + for (y = 0; y < OldH; y++) { + for (x = 0; x < OldBps; x++) { + iluCurImage->Data[z * iluCurImage->SizeOfPlane + (y + AddY) * iluCurImage->Bps + x + AddX] = + Data[z * OldPlane + y * OldBps + x]; + } + } + } + + ifree(Data); + + return IL_TRUE; +} + +//! Flips an image over its x axis +ILboolean ILAPIENTRY iluFlipImage() { + //ILubyte *StartPtr, *EndPtr; + //ILuint y, d; + ILimage *image = ilGetCurImage(); + + if( image == NULL ) { + ilSetError(ILU_ILLEGAL_OPERATION); + return IL_FALSE; + } + + iFlipBuffer(image->Data,image->Depth,image->Bps,image->Height); + /* + for( d = 0; d < image->Depth; d++ ) { + StartPtr = image->Data + d * image->SizeOfPlane; + EndPtr = image->Data + d * image->SizeOfPlane + + image->SizeOfPlane; + + for( y = 0; y < (image->Height/2); y++ ) { + EndPtr -= image->Bps; + iMemSwap(StartPtr,EndPtr,image->Bps); + StartPtr += image->Bps; + } + } + */ + return IL_TRUE; +} + + +//! Mirrors an image over its y axis +ILboolean ILAPIENTRY iluMirror() { + return iMirror(); +} + + +//! Inverts the alpha in the image +ILboolean ILAPIENTRY iluInvertAlpha() { + ILuint i, *IntPtr, NumPix; + ILubyte *Data; + ILushort *ShortPtr; + ILfloat *FltPtr; + ILdouble *DblPtr; + ILubyte Bpp; + + iluCurImage = ilGetCurImage(); + if (iluCurImage == NULL) { + ilSetError(ILU_ILLEGAL_OPERATION); + return IL_FALSE; + } + + if (iluCurImage->Format != IL_RGBA && + iluCurImage->Format != IL_BGRA && + iluCurImage->Format != IL_LUMINANCE_ALPHA) { + ilSetError(ILU_ILLEGAL_OPERATION); + return IL_FALSE; + } + + Data = iluCurImage->Data; + Bpp = iluCurImage->Bpp; + NumPix = iluCurImage->Width * iluCurImage->Height * iluCurImage->Depth; + + switch (iluCurImage->Type) + { + case IL_BYTE: + case IL_UNSIGNED_BYTE: + Data += (Bpp - 1); + for( i = Bpp - 1; i < NumPix; i++, Data += Bpp ) + *(Data) = ~*(Data); + break; + + case IL_SHORT: + case IL_UNSIGNED_SHORT: + ShortPtr = ((ILushort*)Data) + Bpp-1; + for (i = Bpp - 1; i < NumPix; i++, ShortPtr += Bpp) + *(ShortPtr) = ~*(ShortPtr); + break; + + case IL_INT: + case IL_UNSIGNED_INT: + IntPtr = ((ILuint*)Data) + Bpp-1; + for (i = Bpp - 1; i < NumPix; i++, IntPtr += Bpp) + *(IntPtr) = ~*(IntPtr); + break; + + case IL_FLOAT: + FltPtr = ((ILfloat*)Data) + Bpp - 1; + for (i = Bpp - 1; i < NumPix; i++, FltPtr += Bpp) + *(FltPtr) = 1.0f - *(FltPtr); + break; + + case IL_DOUBLE: + DblPtr = ((ILdouble*)Data) + Bpp - 1; + for (i = Bpp - 1; i < NumPix; i++, DblPtr += Bpp) + *(DblPtr) = 1.0f - *(DblPtr); + break; + } + + return IL_TRUE; +} + + +//! Inverts the colours in the image +ILboolean ILAPIENTRY iluNegative() +{ + ILuint i, j, c, *IntPtr, NumPix, Bpp; + ILubyte *Data; + ILushort *ShortPtr; + ILubyte *RegionMask; + + iluCurImage = ilGetCurImage(); + if (iluCurImage == NULL) { + ilSetError(ILU_ILLEGAL_OPERATION); + return IL_FALSE; + } + + if (iluCurImage->Format == IL_COLOUR_INDEX) { + if (!iluCurImage->Pal.Palette || !iluCurImage->Pal.PalSize || iluCurImage->Pal.PalType == IL_PAL_NONE) { + ilSetError(ILU_ILLEGAL_OPERATION); + return IL_FALSE; + } + Data = iluCurImage->Pal.Palette; + i = iluCurImage->Pal.PalSize; + } + else { + Data = iluCurImage->Data; + i = iluCurImage->SizeOfData; + } + + RegionMask = iScanFill(); + + // @TODO: Optimize this some. + + NumPix = i / iluCurImage->Bpc; + Bpp = iluCurImage->Bpp; + + if (RegionMask) { + switch (iluCurImage->Bpc) + { + case 1: + for (j = 0, i = 0; j < NumPix; j += Bpp, i++, Data += Bpp) { + for (c = 0; c < Bpp; c++) { + if (RegionMask[i]) + *(Data+c) = ~*(Data+c); + } + } + break; + + case 2: + ShortPtr = (ILushort*)Data; + for (j = 0, i = 0; j < NumPix; j += Bpp, i++, ShortPtr += Bpp) { + for (c = 0; c < Bpp; c++) { + if (RegionMask[i]) + *(ShortPtr+c) = ~*(ShortPtr+c); + } + } + break; + + case 4: + IntPtr = (ILuint*)Data; + for (j = 0, i = 0; j < NumPix; j += Bpp, i++, IntPtr += Bpp) { + for (c = 0; c < Bpp; c++) { + if (RegionMask[i]) + *(IntPtr+c) = ~*(IntPtr+c); + } + } + break; + } + } + else { + switch (iluCurImage->Bpc) + { + case 1: + for (j = 0; j < NumPix; j++, Data++) { + *(Data) = ~*(Data); + } + break; + + case 2: + ShortPtr = (ILushort*)Data; + for (j = 0; j < NumPix; j++, ShortPtr++) { + *(ShortPtr) = ~*(ShortPtr); + } + break; + + case 4: + IntPtr = (ILuint*)Data; + for (j = 0; j < NumPix; j++, IntPtr++) { + *(IntPtr) = ~*(IntPtr); + } + break; + } + } + + ifree(RegionMask); + + return IL_TRUE; +} + + +// Taken from +// http://www-classic.be.com/aboutbe/benewsletter/volume_III/Issue2.html#Insight +// Hope they don't mind too much. =] +ILboolean ILAPIENTRY iluWave(ILfloat Angle) +{ + ILint Delta; + ILuint y; + ILubyte *DataPtr, *TempBuff; + + iluCurImage = ilGetCurImage(); + if (iluCurImage == NULL) { + ilSetError(ILU_ILLEGAL_OPERATION); + return IL_FALSE; + } + + TempBuff = (ILubyte*)ialloc(iluCurImage->SizeOfData); + if (TempBuff == NULL) { + return IL_FALSE; + } + + for (y = 0; y < iluCurImage->Height; y++) { + Delta = (ILint) + (30 * sin((10 * Angle + y) * IL_DEGCONV) + + 15 * sin(( 7 * Angle + 3 * y) * IL_DEGCONV)); + + DataPtr = iluCurImage->Data + y * iluCurImage->Bps; + + if (Delta < 0) { + Delta = -Delta; + memcpy(TempBuff, DataPtr, iluCurImage->Bpp * Delta); + memcpy(DataPtr, DataPtr + iluCurImage->Bpp * Delta, iluCurImage->Bpp * (iluCurImage->Width - Delta)); + memcpy(DataPtr + iluCurImage->Bpp * (iluCurImage->Width - Delta), TempBuff, iluCurImage->Bpp * Delta); + } + else if (Delta > 0) { + memcpy(TempBuff, DataPtr, iluCurImage->Bpp * (iluCurImage->Width - Delta)); + memcpy(DataPtr, DataPtr + iluCurImage->Bpp * (iluCurImage->Width - Delta), iluCurImage->Bpp * Delta); + memcpy(DataPtr + iluCurImage->Bpp * Delta, TempBuff, iluCurImage->Bpp * (iluCurImage->Width - Delta)); + } + } + + ifree(TempBuff); + + return IL_TRUE; +} + + +// Swaps the colour order of the current image (rgb(a)->bgr(a) or vice-versa). +// Must be either an 8, 24 or 32-bit (coloured) image (or palette). +ILboolean ILAPIENTRY iluSwapColours() { + // Use ilConvert or other like that to convert the data? + // and extend that function to work even on paletted data + + ILimage *img = ilGetCurImage(); + if( img == NULL ) { + ilSetError(ILU_ILLEGAL_OPERATION); + return IL_FALSE; + } + + if (iluCurImage->Bpp == 1) { + if (ilGetBppPal(iluCurImage->Pal.PalType) == 0 || iluCurImage->Format != IL_COLOUR_INDEX) { + ilSetError(ILU_ILLEGAL_OPERATION); // Can be luminance. + return IL_FALSE; + } + + switch( img->Pal.PalType ) { + case IL_PAL_RGB24: + return ilConvertPal(IL_PAL_BGR24); + case IL_PAL_RGB32: + return ilConvertPal(IL_PAL_BGR32); + case IL_PAL_RGBA32: + return ilConvertPal(IL_PAL_BGRA32); + case IL_PAL_BGR24: + return ilConvertPal(IL_PAL_RGB24); + case IL_PAL_BGR32: + return ilConvertPal(IL_PAL_RGB32); + case IL_PAL_BGRA32: + return ilConvertPal(IL_PAL_RGBA32); + default: + ilSetError(ILU_INTERNAL_ERROR); + return IL_FALSE; + } + } + + switch( img->Format) { + case IL_RGB: + return ilConvertImage(IL_BGR, img->Type); + case IL_RGBA: + return ilConvertImage(IL_BGRA, img->Type); + case IL_BGR: + return ilConvertImage(IL_RGB, img->Type); + case IL_BGRA: + return ilConvertImage(IL_RGBA, img->Type); + } + + ilSetError(ILU_INTERNAL_ERROR); + return IL_FALSE; +} + + +typedef struct BUCKET { ILubyte Colours[4]; struct BUCKET *Next; } BUCKET; + +ILuint ILAPIENTRY iluColoursUsed() +{ + ILuint i, c, Bpp, ColVal, SizeData, BucketPos = 0, NumCols = 0; + BUCKET Buckets[8192], *Temp; + ILubyte ColTemp[4]; + ILboolean Matched; + BUCKET *Heap[9]; + ILuint HeapPos = 0, HeapPtr = 0, HeapSize; + + imemclear(Buckets, sizeof(BUCKET) * 8192); + for (c = 0; c < 9; c++) { + Heap[c] = 0; + } + + iluCurImage = ilGetCurImage(); + if (iluCurImage == NULL) { + ilSetError(ILU_ILLEGAL_OPERATION); + return 0; + } + + Bpp = iluCurImage->Bpp; + SizeData = iluCurImage->SizeOfData; + + // Create our miniature memory heap. + // I have determined that the average number of colours versus + // the number of pixels is about a 1:8 ratio, so divide by 8. + HeapSize = IL_MAX(1, iluCurImage->SizeOfData / iluCurImage->Bpp / 8); + Heap[0] = (BUCKET*)ialloc(HeapSize * sizeof(BUCKET)); + if (Heap[0] == NULL) + return IL_FALSE; + + for (i = 0; i < SizeData; i += Bpp) { + *(ILuint*)ColTemp = 0; + /*for (c = 0; c < Bpp; c++) { + ColTemp[c] = iluCurImage->Data[i + c]; + }*/ + ColTemp[0] = iluCurImage->Data[i]; + if (Bpp > 1) { + ColTemp[1] = iluCurImage->Data[i + 1]; + ColTemp[2] = iluCurImage->Data[i + 2]; + } + if (Bpp > 3) + ColTemp[3] = iluCurImage->Data[i + 3]; + + BucketPos = *(ILuint*)ColTemp % 8192; + + // Add to hash table + if (Buckets[BucketPos].Next == NULL) { + NumCols++; + //Buckets[BucketPos].Next = (BUCKET*)ialloc(sizeof(BUCKET)); + Buckets[BucketPos].Next = Heap[HeapPos] + HeapPtr++; + if (HeapPtr >= HeapSize) { + Heap[++HeapPos] = (BUCKET*)ialloc(HeapSize * sizeof(BUCKET)); + if (Heap[HeapPos] == NULL) + goto alloc_error; + HeapPtr = 0; + } + *(ILuint*)Buckets[BucketPos].Next->Colours = *(ILuint*)ColTemp; + Buckets[BucketPos].Next->Next = NULL; + } + else { + Matched = IL_FALSE; + Temp = Buckets[BucketPos].Next; + + ColVal = *(ILuint*)ColTemp; + while (Temp->Next != NULL) { + if (ColVal == *(ILuint*)Temp->Colours) { + Matched = IL_TRUE; + break; + } + Temp = Temp->Next; + } + if (!Matched) { + if (ColVal != *(ILuint*)Temp->Colours) { // Check against last entry + NumCols++; + Temp = Buckets[BucketPos].Next; + //Buckets[BucketPos].Next = (BUCKET*)ialloc(sizeof(BUCKET)); + Buckets[BucketPos].Next = Heap[HeapPos] + HeapPtr++; + if (HeapPtr >= HeapSize) { + Heap[++HeapPos] = (BUCKET*)ialloc(HeapSize * sizeof(BUCKET)); + if (Heap[HeapPos] == NULL) + goto alloc_error; + HeapPtr = 0; + } + Buckets[BucketPos].Next->Next = Temp; + *(ILuint*)Buckets[BucketPos].Next->Colours = *(ILuint*)ColTemp; + } + } + } + } + + // Delete our mini heap. + for (i = 0; i < 9; i++) { + if (Heap[i] == NULL) + break; + ifree(Heap[i]); + } + + return NumCols; + +alloc_error: + for (i = 0; i < 9; i++) { + ifree(Heap[i]); + } + + return 0; +} + + +ILboolean ILAPIENTRY iluCompareImage(ILuint Comp) +{ + ILimage *Original; + ILuint OrigName, i; + ILboolean Same = IL_TRUE; + + iluCurImage = ilGetCurImage(); + OrigName = ilGetCurName(); + + // Same image, so return true. + if (ilGetCurName() == Comp) + return IL_TRUE; + + if (iluCurImage == NULL || ilIsImage(Comp) == IL_FALSE) { + ilSetError(ILU_ILLEGAL_OPERATION); + return 0; + } + + ilBindImage(Comp); + Original = ilGetCurImage(); + + // @TODO: Should we check palettes, too? + if (Original->Bpp != iluCurImage->Bpp || + Original->Depth != iluCurImage->Depth || + Original->Format != iluCurImage->Format || + Original->Height != iluCurImage->Height || + Original->Origin != iluCurImage->Origin || + Original->Type != iluCurImage->Type || + Original->Width != iluCurImage->Width) { + ilBindImage(OrigName); + return IL_FALSE; + } + + for (i = 0; i < iluCurImage->SizeOfData; i++) { + if (Original->Data[i] != iluCurImage->Data[i]) { + Same = IL_FALSE; + break; + } + } + + ilBindImage(OrigName); + return Same; +} + + +// @TODO: FIX ILGETCLEARCALL! +ILboolean ILAPIENTRY iluReplaceColour(ILubyte Red, ILubyte Green, ILubyte Blue, ILfloat Tolerance) +{ + ILubyte ClearCol[4]; + ILint TolVal, Distance, Dist1, Dist2, Dist3; + ILuint i, NumPix; + + iluCurImage = ilGetCurImage(); + if (iluCurImage == NULL) { + ilSetError(ILU_ILLEGAL_OPERATION); + return 0; + } + + ilGetClear(ClearCol, IL_RGBA, IL_UNSIGNED_BYTE); + if (Tolerance > 1.0f || Tolerance < -1.0f) + Tolerance = 1.0f; // Clamp it. + TolVal = (ILuint)(fabs(Tolerance) * UCHAR_MAX); // To be changed. + NumPix = iluCurImage->Width * iluCurImage->Height * iluCurImage->Depth; + + if (Tolerance <= FLT_EPSILON && Tolerance >= 0) { + + //@TODO what is this? + } + else { + switch (iluCurImage->Format) + { + case IL_RGB: + case IL_RGBA: + for (i = 0; i < iluCurImage->SizeOfData; i += iluCurImage->Bpp) { + Dist1 = (ILint)iluCurImage->Data[i] - (ILint)ClearCol[0]; + Dist2 = (ILint)iluCurImage->Data[i+1] - (ILint)ClearCol[1]; + Dist3 = (ILint)iluCurImage->Data[i+2] - (ILint)ClearCol[2]; + Distance = (ILint)sqrt((float)(Dist1 * Dist1 + Dist2 * Dist2 + Dist3 * Dist3)); + if (Distance >= -TolVal && Distance <= TolVal) { + iluCurImage->Data[i] = Red; + iluCurImage->Data[i+1] = Green; + iluCurImage->Data[i+2] = Blue; + } + } + break; + case IL_BGR: + case IL_BGRA: + for (i = 0; i < iluCurImage->SizeOfData; i += iluCurImage->Bpp) { + Dist1 = (ILint)iluCurImage->Data[i] - (ILint)ClearCol[0]; + Dist2 = (ILint)iluCurImage->Data[i+1] - (ILint)ClearCol[1]; + Dist3 = (ILint)iluCurImage->Data[i+2] - (ILint)ClearCol[2]; + Distance = (ILint)sqrt((float)(Dist1 * Dist1 + Dist2 * Dist2 + Dist3 * Dist3)); + if (Distance >= -TolVal && Distance <= TolVal) { + iluCurImage->Data[i+2] = Red; + iluCurImage->Data[i+1] = Green; + iluCurImage->Data[i] = Blue; + } + } + break; + case IL_LUMINANCE: + case IL_LUMINANCE_ALPHA: + for (i = 0; i < iluCurImage->SizeOfData; i += iluCurImage->Bpp) { + Dist1 = (ILint)iluCurImage->Data[i] - (ILint)ClearCol[0]; + if (Dist1 >= -TolVal && Dist1 <= TolVal) { + iluCurImage->Data[i] = Blue; + } + } + break; + //case IL_COLOUR_INDEX: // @TODO + } + } + + return IL_TRUE; +} + + +// Credit goes to Lionel Brits for this (refer to credits.txt) +ILboolean ILAPIENTRY iluEqualize() { + ILuint Histogram[256]; // image Histogram + ILuint SumHistm[256]; // normalized Histogram and LUT + ILuint i = 0; // index variable + ILuint j = 0; // index variable + ILuint Sum=0; + ILuint NumPixels, Bpp; + ILint Intensity; + ILfloat Scale; + ILint IntensityNew; + ILimage *LumImage; + ILuint NewColour[4]; + ILubyte *BytePtr; + ILushort *ShortPtr; + ILuint *IntPtr; + + NewColour[0] = NewColour[1] = NewColour[2] = NewColour[3] = 0; + + iluCurImage = ilGetCurImage(); + if (iluCurImage == NULL) { + ilSetError(ILU_ILLEGAL_OPERATION); + return 0; + } + + // @TODO: Change to work with other types! + if (iluCurImage->Bpc > 1) { + ilSetError(ILU_INTERNAL_ERROR); + return IL_FALSE; + } + + if (iluCurImage->Format == IL_COLOUR_INDEX) { + NumPixels = iluCurImage->Pal.PalSize / ilGetBppPal(iluCurImage->Pal.PalType); + Bpp = ilGetBppPal(iluCurImage->Pal.PalType); + } else { + NumPixels = iluCurImage->Width * iluCurImage->Height * iluCurImage->Depth; + Bpp = iluCurImage->Bpp; + } + + // Clear the tables. + imemclear(Histogram, 256 * sizeof(ILuint)); + imemclear(SumHistm, 256 * sizeof(ILuint)); + + LumImage = iConvertImage(iluCurImage, IL_LUMINANCE, IL_UNSIGNED_BYTE); // the type must be left as it is! + if (LumImage == NULL) + return IL_FALSE; + for (i = 0; i < NumPixels; i++) { + Histogram[LumImage->Data[i]]++; + } + + // Calculate normalized Sum of Histogram. + for (i = 0; i < 256; i++) { + for (j = 0; j < i; j++) + Sum += Histogram[j]; + + SumHistm[i] = (Sum << 8) / NumPixels; + Sum = 0; + } + + + BytePtr = (iluCurImage->Format == IL_COLOUR_INDEX) ? iluCurImage->Pal.Palette : iluCurImage->Data; + ShortPtr = (ILushort*)iluCurImage->Data; + IntPtr = (ILuint*)iluCurImage->Data; + + // Transform image using new SumHistm as a LUT + for (i = 0; i < NumPixels; i++) { + Intensity = LumImage->Data[i]; + + // Look up the normalized intensity + IntensityNew = (ILint)SumHistm[Intensity]; + + // Find out by how much the intensity has been Scaled + Scale = (ILfloat)IntensityNew / (ILfloat)Intensity; + + switch (iluCurImage->Bpc) + { + case 1: + // Calculate new pixel(s) + NewColour[0] = (ILuint)(BytePtr[i * iluCurImage->Bpp] * Scale); + if (Bpp >= 3) { + NewColour[1] = (ILuint)(BytePtr[i * iluCurImage->Bpp + 1] * Scale); + NewColour[2] = (ILuint)(BytePtr[i * iluCurImage->Bpp + 2] * Scale); + } + + // Clamp values + if (NewColour[0] > UCHAR_MAX) + NewColour[0] = UCHAR_MAX; + if (Bpp >= 3) { + if (NewColour[1] > UCHAR_MAX) + NewColour[1] = UCHAR_MAX; + if (NewColour[2] > UCHAR_MAX) + NewColour[2] = UCHAR_MAX; + } + + // Store pixel(s) + BytePtr[i * iluCurImage->Bpp] = (ILubyte)NewColour[0]; + if (Bpp >= 3) { + BytePtr[i * iluCurImage->Bpp + 1] = (ILubyte)NewColour[1]; + BytePtr[i * iluCurImage->Bpp + 2] = (ILubyte)NewColour[2]; + } + break; + + /*case 2: + // Calculate new pixel + NewColour[0] = (ILuint)(ShortPtr[i * iluCurImage->Bpp] * Scale); + NewColour[1] = (ILuint)(ShortPtr[i * iluCurImage->Bpp + 1] * Scale); + NewColour[2] = (ILuint)(ShortPtr[i * iluCurImage->Bpp + 2] * Scale); + + // Clamp values + if (NewColour[0] > USHRT_MAX) + NewColour[0] = USHRT_MAX; + if (NewColour[1] > USHRT_MAX) + NewColour[1] = USHRT_MAX; + if (NewColour[2] > USHRT_MAX) + NewColour[2] = USHRT_MAX; + + // Store pixel + ShortPtr[i * iluCurImage->Bpp] = (ILushort)NewColour[0]; + ShortPtr[i * iluCurImage->Bpp + 1] = (ILushort)NewColour[1]; + ShortPtr[i * iluCurImage->Bpp + 2] = (ILushort)NewColour[2]; + break; + + case 4: + // Calculate new pixel + NewColour[0] = (ILuint)(IntPtr[i * iluCurImage->Bpp] * Scale); + NewColour[1] = (ILuint)(IntPtr[i * iluCurImage->Bpp + 1] * Scale); + NewColour[2] = (ILuint)(IntPtr[i * iluCurImage->Bpp + 2] * Scale); + + // Clamp values + if (NewColour[0] > UINT_MAX) + NewColour[0] = UINT_MAX; + if (NewColour[1] > UINT_MAX) + NewColour[1] = UINT_MAX; + if (NewColour[2] > UINT_MAX) + NewColour[2] = UINT_MAX; + + // Store pixel + IntPtr[i * 4 * iluCurImage->Bpp] = NewColour[0]; + IntPtr[i * 4 * iluCurImage->Bpp + 1] = NewColour[1]; + IntPtr[i * 4 * iluCurImage->Bpp + 2] = NewColour[2]; + break;*/ + } + } + + ilCloseImage(LumImage); + + return IL_TRUE; +} + + +// Method from the paper "Underwater image quality enhancement through composition of +// dual - intensity images and Rayleigh - stretching" by Ghani and Isa +// (http://springerplus.springeropen.com/articles/10.1186/2193-1801-3-757), +// DOI : 10.1186 / 2193 - 1801 - 3 - 757 +// Note that the ordering of the colors does not matter for the first part of this method. +ILboolean ILAPIENTRY iluEqualize2(void) +{ + iluCurImage = ilGetCurImage(); + if (iluCurImage == NULL) { + ilSetError(ILU_ILLEGAL_OPERATION); + return 0; + } + + // @TODO: Change to work with other types! + if (iluCurImage->Bpc > 1 || (iluCurImage->Format != IL_RGB && iluCurImage->Format != IL_RGBA + && iluCurImage->Format != IL_BGR && iluCurImage->Format != IL_BGRA)) { + ilSetError(ILU_INTERNAL_ERROR); + return IL_FALSE; + } + + // Start of the Modified Von Kries hypothesis + + ILdouble ChanAvgs[3] = { 0.0, 0.0, 0.0 }; + ILuint NumPix = iluCurImage->Width * iluCurImage->Height; + if (NumPix < 1) { + ilSetError(IL_INTERNAL_ERROR); + return IL_FALSE; + } + for (ILuint i = 0; i < iluCurImage->SizeOfData; i += iluCurImage->Bpp) + { + ChanAvgs[0] += iluCurImage->Data[i + 0]; + ChanAvgs[1] += iluCurImage->Data[i + 1]; + ChanAvgs[2] += iluCurImage->Data[i + 2]; + } + ChanAvgs[0] /= NumPix; + ChanAvgs[1] /= NumPix; + ChanAvgs[2] /= NumPix; + + //@TODO: This is a really crude way of sorting the array - could be much simpler code + // in C++ or using an actual sorting function. With only 3 elements, this isn't too bad. + ILdouble ChanAvgsCopy[3]; + ChanAvgsCopy[0] = IL_MIN(ChanAvgs[0], IL_MIN(ChanAvgs[1], ChanAvgs[2])); + ChanAvgsCopy[2] = IL_MAX(ChanAvgs[0], IL_MAX(ChanAvgs[1], ChanAvgs[2])); + ChanAvgsCopy[1] = -1; // Just a dummy value + + ILuint MinPos = -1, MaxPos = -1; + for (ILuint i = 0; i < 3; i++) + { + if (ChanAvgs[i] == ChanAvgsCopy[0]) + MinPos = i; + if (ChanAvgs[i] == ChanAvgsCopy[2]) + MaxPos = i; + } + for (ILuint i = 0; i < 3; i++) + { + if (i != MinPos && i != MaxPos) + ChanAvgsCopy[1] = ChanAvgs[i]; + } + + if (ChanAvgsCopy[0] < 1.0 || ChanAvgsCopy[2] < 1.0) { + // This prevents division by 0 - could possibly be lowered less than 1 + //ilSetError(IL_INTERNAL_ERROR); + return IL_FALSE; + } + + ILdouble A = ChanAvgsCopy[1] / ChanAvgsCopy[0]; // Median of RGB divided by minimum of RGB + ILdouble B = ChanAvgsCopy[1] / ChanAvgsCopy[2]; // Median of RGB divided by maximum of RGB + + ILdouble *Corrected = (ILdouble*)ialloc(iluCurImage->SizeOfData * sizeof(ILdouble)); + if (Corrected == NULL) { + return IL_FALSE; + } + + // Make a copy of the data as doubles + for (ILuint i = 0; i < iluCurImage->SizeOfData; i++) + Corrected[i] = iluCurImage->Data[i]; + + for (ILuint i = 0; i < iluCurImage->SizeOfData; i += iluCurImage->Bpp) + { + // These values can overflow + Corrected[i + MinPos] = iluCurImage->Data[i + MinPos] * A; + Corrected[i + MaxPos] = iluCurImage->Data[i + MaxPos] * B; + } + + ILdouble MinVals[3] = { 1e9, 1e9, 1e9 }, MaxVals[3] = { -1, -1, -1 }; + //@TODO: This could be rolled into the averaging loop, since we can just scale these by A and B + for (ILuint i = 0; i < iluCurImage->SizeOfData; i += iluCurImage->Bpp) + { + for (ILuint c = 0; c < 3; c++) { + if (Corrected[i + c] > MaxVals[c]) + MaxVals[c] = Corrected[i + c]; + if (Corrected[i + c] < MinVals[c]) + MinVals[c] = Corrected[i + c]; + } + } + + // Histogram stretching + + for (ILuint c = 0; c < 3; c++) { + if ((MaxVals[c] - MinVals[c]) < 1.0) { + // This is the case if an image is a solid color. The original image is unmodified. + return IL_FALSE; + } + } + + for (ILuint i = 0; i < iluCurImage->SizeOfData; i += iluCurImage->Bpp) + { + for (ILuint c = 0; c < 3; c++) { + iluCurImage->Data[i + c] = (ILubyte)((Corrected[i + c] - MinVals[c]) * ((255.0 - 0.0) / (MaxVals[c] - MinVals[c])) + 0); + } + } + + ifree(Corrected); + + return IL_TRUE; +} + |