// Very simple right now. // This will probably use Perlin noise and parameters in the future. ILboolean ILAPIENTRY iluNoisify(ILclampf Tolerance) { ILuint i, j, c, Factor, Factor2, NumPix; ILint Val; ILushort *ShortPtr; ILuint *IntPtr; ILubyte *RegionMask; iluCurImage = ilGetCurImage(); if (iluCurImage == NULL) { ilSetError(ILU_ILLEGAL_OPERATION); return IL_FALSE; } RegionMask = iScanFill(); // @TODO: Change this to work correctly without time()! //srand(time(NULL)); NumPix = iluCurImage->SizeOfData / iluCurImage->Bpc; switch (iluCurImage->Bpc) { case 1: Factor = (ILubyte)(Tolerance * (UCHAR_MAX / 2)); if (Factor == 0) return IL_TRUE; Factor2 = Factor + Factor; for (i = 0, j = 0; i < NumPix; i += iluCurImage->Bpp, j++) { if (RegionMask) { if (!RegionMask[j]) continue; } Val = (ILint)((ILint)(rand() % Factor2) - Factor); for (c = 0; c < iluCurImage->Bpp; c++) { if ((ILint)iluCurImage->Data[i + c] + Val > UCHAR_MAX) iluCurImage->Data[i + c] = UCHAR_MAX; else if ((ILint)iluCurImage->Data[i + c] + Val < 0) iluCurImage->Data[i + c] = 0; else iluCurImage->Data[i + c] += Val; } } break; case 2: Factor = (ILushort)(Tolerance * (USHRT_MAX / 2)); if (Factor == 0) return IL_TRUE; Factor2 = Factor + Factor; ShortPtr = (ILushort*)iluCurImage->Data; for (i = 0, j = 0; i < NumPix; i += iluCurImage->Bpp, j++) { if (RegionMask) { if (!RegionMask[j]) continue; } Val = (ILint)((ILint)(rand() % Factor2) - Factor); for (c = 0; c < iluCurImage->Bpp; c++) { if ((ILint)ShortPtr[i + c] + Val > USHRT_MAX) ShortPtr[i + c] = USHRT_MAX; else if ((ILint)ShortPtr[i + c] + Val < 0) ShortPtr[i + c] = 0; else ShortPtr[i + c] += Val; } } break; case 4: Factor = (ILuint)(Tolerance * (UINT_MAX / 2)); if (Factor == 0) return IL_TRUE; Factor2 = Factor + Factor; IntPtr = (ILuint*)iluCurImage->Data; for (i = 0, j = 0; i < NumPix; i += iluCurImage->Bpp, j++) { if (RegionMask) { if (!RegionMask[j]) continue; } Val = (ILint)((ILint)(rand() % Factor2) - Factor); for (c = 0; c < iluCurImage->Bpp; c++) { if (IntPtr[i + c] + Val > UINT_MAX) IntPtr[i + c] = UINT_MAX; else if ((ILint)IntPtr[i + c] + Val < 0) IntPtr[i + c] = 0; else IntPtr[i + c] += Val; } } break; } ifree(RegionMask); return IL_TRUE; }
// Could probably be optimized a bit...too many nested for loops. //! Pixelizes an image ILboolean ILAPIENTRY iluPixelize(ILuint PixSize) { ILuint x, y, z, i, j, k, c, r, Total, Tested; ILushort *ShortPtr; ILuint *IntPtr; ILdouble *DblPtr, DblTotal, DblTested; ILubyte *RegionMask; iluCurImage = ilGetCurImage(); if (iluCurImage == NULL) { ilSetError(ILU_ILLEGAL_OPERATION); return IL_FALSE; } if (PixSize == 0) PixSize = 1; r = 0; if (iluCurImage->Format == IL_COLOUR_INDEX) ilConvertImage(ilGetPalBaseType(iluCurImage->Pal.PalType), IL_UNSIGNED_BYTE); RegionMask = iScanFill(); switch (iluCurImage->Bpc) { case 1: for (z = 0; z < iluCurImage->Depth; z += PixSize) { for (y = 0; y < iluCurImage->Height; y += PixSize) { for (x = 0; x < iluCurImage->Width; x += PixSize) { for (c = 0; c < iluCurImage->Bpp; c++) { Total = 0; Tested = 0; for (k = 0; k < PixSize && z+k < iluCurImage->Depth; k++) { for (j = 0; j < PixSize && y+j < iluCurImage->Height; j++) { for (i = 0; i < PixSize && x+i < iluCurImage->Width; i++, Tested++) { Total += iluCurImage->Data[(z+k) * iluCurImage->SizeOfPlane + (y+j) * iluCurImage->Bps + (x+i) * iluCurImage->Bpp + c]; } } } Total /= Tested; for (k = 0; k < PixSize && z+k < iluCurImage->Depth; k++) { for (j = 0; j < PixSize && y+j < iluCurImage->Height; j++) { for (i = 0; i < PixSize && x+i < iluCurImage->Width; i++, Tested++) { if (RegionMask) { if (!RegionMask[(y+j) * iluCurImage->Width + (x+i)]) continue; } iluCurImage->Data[(z+k) * iluCurImage->SizeOfPlane + (y+j) * iluCurImage->Bps + (x+i) * iluCurImage->Bpp + c] = Total; } } } } } } } break; case 2: ShortPtr = (ILushort*)iluCurImage->Data; iluCurImage->Bps /= 2; for (z = 0; z < iluCurImage->Depth; z += PixSize) { for (y = 0; y < iluCurImage->Height; y += PixSize) { for (x = 0; x < iluCurImage->Width; x += PixSize, r += PixSize) { for (c = 0; c < iluCurImage->Bpp; c++) { Total = 0; Tested = 0; for (k = 0; k < PixSize && z+k < iluCurImage->Depth; k++) { for (j = 0; j < PixSize && y+j < iluCurImage->Height; j++) { for (i = 0; i < PixSize && x+i < iluCurImage->Width; i++, Tested++) { Total += ShortPtr[(z+k) * iluCurImage->SizeOfPlane + (y+j) * iluCurImage->Bps + (x+i) * iluCurImage->Bpp + c]; } } } Total /= Tested; for (k = 0; k < PixSize && z+k < iluCurImage->Depth; k++) { for (j = 0; j < PixSize && y+j < iluCurImage->Height; j++) { for (i = 0; i < PixSize && x+i < iluCurImage->Width; i++, Tested++) { if (RegionMask[r+i]) { ShortPtr[(z+k) * iluCurImage->SizeOfPlane + (y+j) * iluCurImage->Bps + (x+i) * iluCurImage->Bpp + c] = Total; } } } } } } } } iluCurImage->Bps *= 2; break; case 4: IntPtr = (ILuint*)iluCurImage->Data; iluCurImage->Bps /= 4; for (z = 0; z < iluCurImage->Depth; z += PixSize) { for (y = 0; y < iluCurImage->Height; y += PixSize) { for (x = 0; x < iluCurImage->Width; x += PixSize, r += PixSize) { for (c = 0; c < iluCurImage->Bpp; c++) { Total = 0; Tested = 0; for (k = 0; k < PixSize && z+k < iluCurImage->Depth; k++) { for (j = 0; j < PixSize && y+j < iluCurImage->Height; j++) { for (i = 0; i < PixSize && x+i < iluCurImage->Width; i++, Tested++) { Total += IntPtr[(z+k) * iluCurImage->SizeOfPlane + (y+j) * iluCurImage->Bps + (x+i) * iluCurImage->Bpp + c]; } } } Total /= Tested; for (k = 0; k < PixSize && z+k < iluCurImage->Depth; k++) { for (j = 0; j < PixSize && y+j < iluCurImage->Height; j++) { for (i = 0; i < PixSize && x+i < iluCurImage->Width; i++, Tested++) { if (RegionMask[r+i]) { IntPtr[(z+k) * iluCurImage->SizeOfPlane + (y+j) * iluCurImage->Bps + (x+i) * iluCurImage->Bpp + c] = Total; } } } } } } } } iluCurImage->Bps *= 4; break; case 8: DblPtr = (ILdouble*)iluCurImage->Data; iluCurImage->Bps /= 8; for (z = 0; z < iluCurImage->Depth; z += PixSize) { for (y = 0; y < iluCurImage->Height; y += PixSize) { for (x = 0; x < iluCurImage->Width; x += PixSize, r += PixSize) { for (c = 0; c < iluCurImage->Bpp; c++) { DblTotal = 0.0; DblTested = 0.0; for (k = 0; k < PixSize && z+k < iluCurImage->Depth; k++) { for (j = 0; j < PixSize && y+j < iluCurImage->Height; j++) { for (i = 0; i < PixSize && x+i < iluCurImage->Width; i++, DblTested++) { DblTotal += DblPtr[(z+k) * iluCurImage->SizeOfPlane + (y+j) * iluCurImage->Bps + (x+i) * iluCurImage->Bpp + c]; } } } DblTotal /= DblTested; for (k = 0; k < PixSize && z+k < iluCurImage->Depth; k++) { for (j = 0; j < PixSize && y+j < iluCurImage->Height; j++) { for (i = 0; i < PixSize && x+i < iluCurImage->Width; i++, DblTested++) { if (RegionMask[r+i]) { DblPtr[(z+k) * iluCurImage->SizeOfPlane + (y+j) * iluCurImage->Bps + (x+i) * iluCurImage->Bpp + c] = DblTotal; } } } } } } } } iluCurImage->Bps *= 8; break; } ifree(RegionMask); return IL_TRUE; }
ILboolean iNoisify(ILimage *Image, ILclampf Tolerance) { ILuint i, j, c, Factor1, Factor2, NumPix; ILint Val; ILubyte *RegionMask; if (Image == NULL) { iSetError(ILU_ILLEGAL_OPERATION); return IL_FALSE; } RegionMask = iScanFill(Image); // @TODO: Change this to work correctly without time()! //srand(time(NULL)); NumPix = Image->SizeOfData / Image->Bpc; switch (Image->Bpc) { case 1: Factor1 = (ILubyte)(Tolerance * IL_MAX_UNSIGNED_BYTE * 0.5f); Factor2 = Factor1 + Factor1; if (Factor1 == 0) return IL_TRUE; for (i = 0, j = 0; i < NumPix; i += Image->Bpp, j++) { if (RegionMask) { if (!RegionMask[j]) continue; } Val = iGetNoiseValue(Factor1, Factor2); for (c = 0; c < Image->Bpp; c++) { ILint NewVal = (ILint)iGetImageDataUByte(Image)[i + c] + Val; if (NewVal > IL_MAX_UNSIGNED_BYTE) iGetImageDataUByte(Image)[i + c] = IL_MAX_UNSIGNED_BYTE; else if (NewVal < 0) iGetImageDataUByte(Image)[i + c] = 0; else iGetImageDataUByte(Image)[i + c] += Val; } } break; case 2: Factor1 = (ILushort)(Tolerance * IL_MAX_UNSIGNED_SHORT * 0.5f); Factor2 = Factor1 + Factor1; if (Factor1 == 0) return IL_TRUE; for (i = 0, j = 0; i < NumPix; i += Image->Bpp, j++) { if (RegionMask) { if (!RegionMask[j]) continue; } Val = iGetNoiseValue(Factor1, Factor2); for (c = 0; c < Image->Bpp; c++) { ILint NewVal = (ILint)iGetImageDataUShort(Image)[i + c] + Val; if (NewVal > IL_MAX_UNSIGNED_SHORT) iGetImageDataUShort(Image)[i + c] = IL_MAX_UNSIGNED_SHORT; else if (NewVal < 0) iGetImageDataUShort(Image)[i + c] = 0; else iGetImageDataUShort(Image)[i + c] = (ILushort)NewVal; } } break; // FIXME: ILfloat, ILdouble case 4: Factor1 = (ILuint)(Tolerance * IL_MAX_UNSIGNED_INT * 0.5f); Factor2 = Factor1 + Factor1; if (Factor1 == 0) return IL_TRUE; for (i = 0, j = 0; i < NumPix; i += Image->Bpp, j++) { if (RegionMask) { if (!RegionMask[j]) continue; } Val = iGetNoiseValue(Factor1, Factor2); for (c = 0; c < Image->Bpp; c++) { ILint64 NewVal = (ILint64)iGetImageDataUInt(Image)[i + c] + Val; if (NewVal > IL_MAX_UNSIGNED_INT) iGetImageDataUInt(Image)[i + c] = IL_MAX_UNSIGNED_INT; else if (NewVal < 0) iGetImageDataUInt(Image)[i + c] = 0; else iGetImageDataUInt(Image)[i + c] = (ILuint)NewVal; } } break; } ifree(RegionMask); return IL_TRUE; }
// Needs some SERIOUS optimization. ILubyte *Filter(ILimage *Image, const ILint *matrix, ILint scale, ILint bias) { ILint x, y, c, LastX, LastY, Offsets[9]; ILuint i, Temp, z; ILubyte *Data, *ImgData, *NewData, *RegionMask; ILdouble Num; if (Image == NULL) { ilSetError(ILU_ILLEGAL_OPERATION); return NULL; } Data = (ILubyte*)ialloc(Image->SizeOfData); if (Data == NULL) { return NULL; } RegionMask = iScanFill(); // Preserve original data. ImgData = Image->Data; NewData = Data; for (z = 0; z < Image->Depth; z++) { LastX = Image->Width - 1; LastY = Image->Height - 1; for (y = 1; y < LastY; y++) { for (x = 1; x < LastX; x++) { Offsets[4] = ((y ) * Image->Width + (x )) * Image->Bpp; if (RegionMask) { if (!RegionMask[y * Image->Width + x]) { for (c = 0; c < Image->Bpp; c++) { Data[Offsets[4]+c] = Image->Data[Offsets[4]+c]; } continue; } } Offsets[0] = ((y-1) * Image->Width + (x-1)) * Image->Bpp; Offsets[1] = ((y-1) * Image->Width + (x )) * Image->Bpp; Offsets[2] = ((y-1) * Image->Width + (x+1)) * Image->Bpp; Offsets[3] = ((y ) * Image->Width + (x-1)) * Image->Bpp; Offsets[5] = ((y ) * Image->Width + (x+1)) * Image->Bpp; Offsets[6] = ((y+1) * Image->Width + (x-1)) * Image->Bpp; Offsets[7] = ((y+1) * Image->Width + (x )) * Image->Bpp; Offsets[8] = ((y+1) * Image->Width + (x-1)) * Image->Bpp; // Always has at least one, so get rid of all those +c's Num = Image->Data[Offsets[0]] * matrix[0] + Image->Data[Offsets[1]] * matrix[1]+ Image->Data[Offsets[2]] * matrix[2]+ Image->Data[Offsets[3]] * matrix[3]+ Image->Data[Offsets[4]] * matrix[4]+ Image->Data[Offsets[5]] * matrix[5]+ Image->Data[Offsets[6]] * matrix[6]+ Image->Data[Offsets[7]] * matrix[7]+ Image->Data[Offsets[8]] * matrix[8]; Temp = (ILuint)fabs((Num / (ILdouble)scale) + bias); if (Temp > 255) Data[Offsets[4]] = 255; else Data[Offsets[4]] = Temp; for (c = 1; c < Image->Bpp; c++) { Num = Image->Data[Offsets[0]+c] * matrix[0]+ Image->Data[Offsets[1]+c] * matrix[1]+ Image->Data[Offsets[2]+c] * matrix[2]+ Image->Data[Offsets[3]+c] * matrix[3]+ Image->Data[Offsets[4]+c] * matrix[4]+ Image->Data[Offsets[5]+c] * matrix[5]+ Image->Data[Offsets[6]+c] * matrix[6]+ Image->Data[Offsets[7]+c] * matrix[7]+ Image->Data[Offsets[8]+c] * matrix[8]; Temp = (ILuint)fabs((Num / (ILdouble)scale) + bias); if (Temp > 255) Data[Offsets[4]+c] = 255; else Data[Offsets[4]+c] = Temp; } } } // Copy 4 corners for (c = 0; c < Image->Bpp; c++) { Data[c] = Image->Data[c]; Data[Image->Bps - Image->Bpp + c] = Image->Data[Image->Bps - Image->Bpp + c]; Data[(Image->Height - 1) * Image->Bps + c] = Image->Data[(Image->Height - 1) * Image->Bps + c]; Data[Image->Height * Image->Bps - Image->Bpp + c] = Image->Data[Image->Height * Image->Bps - Image->Bpp + c]; } // If we only copy the edge pixels, then they receive no filtering, making them // look out of place after several passes of an image. So we filter the edge // rows/columns, duplicating the edge pixels for one side of the "matrix". // First row for (x = 1; x < (ILint)Image->Width-1; x++) { if (RegionMask) { if (!RegionMask[x]) { Data[y + x * Image->Bpp + c] = Image->Data[y + x * Image->Bpp + c]; continue; } } for (c = 0; c < Image->Bpp; c++) { Num = Image->Data[(x-1) * Image->Bpp + c] * matrix[0] + Image->Data[x * Image->Bpp + c] * matrix[1]+ Image->Data[(x+1) * Image->Bpp + c] * matrix[2]+ Image->Data[(x-1) * Image->Bpp + c] * matrix[3]+ Image->Data[x * Image->Bpp + c] * matrix[4]+ Image->Data[(x+1) * Image->Bpp + c] * matrix[5]+ Image->Data[(Image->Width + (x-1)) * Image->Bpp + c] * matrix[6]+ Image->Data[(Image->Width + (x )) * Image->Bpp + c] * matrix[7]+ Image->Data[(Image->Width + (x-1)) * Image->Bpp + c] * matrix[8]; Temp = (ILuint)fabs((Num / (ILdouble)scale) + bias); if (Temp > 255) Data[x * Image->Bpp + c] = 255; else Data[x * Image->Bpp + c] = Temp; } } // Last row y = (Image->Height - 1) * Image->Bps; for (x = 1; x < (ILint)Image->Width-1; x++) { if (RegionMask) { if (!RegionMask[(Image->Height - 1) * Image->Width + x]) { Data[y + x * Image->Bpp + c] = Image->Data[y + x * Image->Bpp + c]; continue; } } for (c = 0; c < Image->Bpp; c++) { Num = Image->Data[y - Image->Bps + (x-1) * Image->Bpp + c] * matrix[0] + Image->Data[y - Image->Bps + x * Image->Bpp + c] * matrix[1]+ Image->Data[y - Image->Bps + (x+1) * Image->Bpp + c] * matrix[2]+ Image->Data[y + (x-1) * Image->Bpp + c] * matrix[3]+ Image->Data[y + x * Image->Bpp + c] * matrix[4]+ Image->Data[y + (x+1) * Image->Bpp + c] * matrix[5]+ Image->Data[y + (x-1) * Image->Bpp + c] * matrix[6]+ Image->Data[y + x * Image->Bpp + c] * matrix[7]+ Image->Data[y + (x-1) * Image->Bpp + c] * matrix[8]; Temp = (ILuint)fabs((Num / (ILdouble)scale) + bias); if (Temp > 255) Data[y + x * Image->Bpp + c] = 255; else Data[y + x * Image->Bpp + c] = Temp; } } // Left side for (i = 1, y = Image->Bps; i < Image->Height-1; i++, y += Image->Bps) { if (RegionMask) { if (!RegionMask[y / Image->Bpp]) { Data[y + c] = Image->Data[y + c]; continue; } } for (c = 0; c < Image->Bpp; c++) { Num = Image->Data[y - Image->Bps + c] * matrix[0] + Image->Data[y - Image->Bps + Image->Bpp + c] * matrix[1]+ Image->Data[y - Image->Bps + 2 * Image->Bpp + c] * matrix[2]+ Image->Data[y + c] * matrix[3]+ Image->Data[y + Image->Bpp + c] * matrix[4]+ Image->Data[y + 2 * Image->Bpp + c] * matrix[5]+ Image->Data[y + Image->Bps + c] * matrix[6]+ Image->Data[y + Image->Bps + Image->Bpp + c] * matrix[7]+ Image->Data[y + Image->Bps + 2 * Image->Bpp + c] * matrix[8]; Temp = (ILuint)fabs((Num / (ILdouble)scale) + bias); if (Temp > 255) Data[y + c] = 255; else Data[y + c] = Temp; } } // Right side for (i = 1, y = Image->Bps * 2 - Image->Bpp; i < Image->Height-1; i++, y += Image->Bps) { if (RegionMask) { if (!RegionMask[y / Image->Bpp + (Image->Width - 1)]) { for (c = 0; c < Image->Bpp; c++) { Data[y + c] = Image->Data[y + c]; } continue; } } for (c = 0; c < Image->Bpp; c++) { Num = Image->Data[y - Image->Bps + c] * matrix[0] + Image->Data[y - Image->Bps + Image->Bpp + c] * matrix[1]+ Image->Data[y - Image->Bps + 2 * Image->Bpp + c] * matrix[2]+ Image->Data[y + c] * matrix[3]+ Image->Data[y + Image->Bpp + c] * matrix[4]+ Image->Data[y + 2 * Image->Bpp + c] * matrix[5]+ Image->Data[y + Image->Bps + c] * matrix[6]+ Image->Data[y + Image->Bps + Image->Bpp + c] * matrix[7]+ Image->Data[y + Image->Bps + 2 * Image->Bpp + c] * matrix[8]; Temp = (ILuint)fabs((Num / (ILdouble)scale) + bias); if (Temp > 255) Data[y + c] = 255; else Data[y + c] = Temp; } } // Go to next "plane". Image->Data += Image->SizeOfPlane; Data += Image->SizeOfPlane; } ifree(RegionMask); // Restore original data. Image->Data = ImgData; Data = NewData; return Data; }