Esempio n. 1
0
static void RandomDitherBitmap(CSBitmap* pBitmap, int ditherAmount)
{
	const int width = GetWidth(pBitmap);
	const int height = GetHeight(pBitmap);
	const int numChannels = GetChannels(pBitmap);
	if (numChannels < 3)
		return;
	for (int y = 0; y < height; ++y)
	{
		uint8_t* pPixel = GetLinePtr(pBitmap, y);
		for (int x = 0; x < width; ++x)
		{
			int offset = (rand() % ditherAmount) - (ditherAmount / 2);
			for (int chan = 0; chan < 3; ++chan)
			{
				int Value = pPixel[chan] + offset;
				if (Value < 0)
					Value = 0;
				if (Value > 255)
					Value = 255;
				pPixel[chan] = Value;
			}
			pPixel += numChannels;
		}
	}
}
Esempio n. 2
0
uint8_t *GetPixelPtr(CSBitmap* pBitmap, int x, int y)
{
	assert(HasBitmap(pBitmap));
	assert(y >= 0 && y < GetHeight(pBitmap));
	assert(x >= 0 && x < GetWidth(pBitmap));
	return GetLinePtr(pBitmap, y) + x * GetChannels(pBitmap);
}
//===========================================================================
//===========================================================================
bool KImage::GaussianBlur(double dblRadius)
{
    bool boolError = false;
    if (BeginDirectAccessOnLines())
    {
        switch(GetPixelBits())
        {
        case 1:
            assert(false);
            boolError = true;
            break;
        case 8:
            {
                BYTE **pLineInput = new BYTE *[intHeight];
                for (int intY = intHeight - 1; intY >= 0; intY--)
                    pLineInput[intY] = (BYTE *)(GetLinePtr(intY));

                __GaussianBlurOneChannel(intWidth, intHeight, pLineInput, pLineInput, dblRadius);

                delete [] pLineInput;
                break;
            }
        case 24:
            {
                BYTE **pLineInput = new BYTE *[intHeight];
                for (int intY = intHeight - 1; intY >= 0; intY--)
                    pLineInput[intY] = new BYTE[intWidth];

                for (int intChannel = 0; intChannel < 3; intChannel++)
                {
                    for (int intY = intHeight - 1; intY >= 0; intY--)
                    {
                        BYTE *line = (BYTE *)GetLinePtr(intY);
                        for (int intX = 0; intX < intWidth; intX++)
                            pLineInput[intY][intX] = line[3 * intX + intChannel];
                    }

                    __GaussianBlurOneChannel(intWidth, intHeight, pLineInput, pLineInput, dblRadius);

                    for (int intY = intHeight - 1; intY >= 0; intY--)
                    {
                        BYTE *line = (BYTE *)GetLinePtr(intY);
                        for (int intX = 0; intX < intWidth; intX++)
                            line[3 * intX + intChannel] = pLineInput[intY][intX];
                    }
                }

                for (int intY = intHeight - 1; intY >= 0; intY--)
                    delete [] pLineInput[intY];
                delete [] pLineInput;

                break;
            }
        default:
            assert(false);
            boolError = true;
            break;
        }

        EndDirectAccessOnLines();
    }

    return !boolError;
}
Esempio n. 4
0
static void OrderedDitherBitmap(CSBitmap* pBitmap, int ditherAmount)
{
	const int DITHERSIZE = 16;
	// A sixteen by sixteen dither table holds 256 values,
	// which is enough to give us dither values from zero to 255.
	int DitherArray[DITHERSIZE][DITHERSIZE] =
	{
		{ 0, 128, 32, 160,  8, 136, 40, 168,  2, 130, 34, 162, 10, 138, 42, 170, },
		{192, 64, 224, 96, 200, 72, 232, 104, 194, 66, 226, 98, 202, 74, 234, 106, },
		{48, 176, 16, 144, 56, 184, 24, 152, 50, 178, 18, 146, 58, 186, 26, 154, },
		{240, 112, 208, 80, 248, 120, 216, 88, 242, 114, 210, 82, 250, 122, 218, 90, },
		{12, 140, 44, 172,  4, 132, 36, 164, 14, 142, 46, 174,  6, 134, 38, 166, },
		{204, 76, 236, 108, 196, 68, 228, 100, 206, 78, 238, 110, 198, 70, 230, 102, },
		{60, 188, 28, 156, 52, 180, 20, 148, 62, 190, 30, 158, 54, 182, 22, 150, },
		{252, 124, 220, 92, 244, 116, 212, 84, 254, 126, 222, 94, 246, 118, 214, 86, },
		{ 3, 131, 35, 163, 11, 139, 43, 171,  1, 129, 33, 161,  9, 137, 41, 169, },
		{195, 67, 227, 99, 203, 75, 235, 107, 193, 65, 225, 97, 201, 73, 233, 105, },
		{51, 179, 19, 147, 59, 187, 27, 155, 49, 177, 17, 145, 57, 185, 25, 153, },
		{243, 115, 211, 83, 251, 123, 219, 91, 241, 113, 209, 81, 249, 121, 217, 89, },
		{15, 143, 47, 175,  7, 135, 39, 167, 13, 141, 45, 173,  5, 133, 37, 165, },
		{207, 79, 239, 111, 199, 71, 231, 103, 205, 77, 237, 109, 197, 69, 229, 101, },
		{63, 191, 31, 159, 55, 183, 23, 151, 61, 189, 29, 157, 53, 181, 21, 149, },
		{255, 127, 223, 95, 247, 119, 215, 87, 253, 125, 221, 93, 245, 117, 213, 85, },
	};
	assert(GetChannels(pBitmap) >= 3);
	assert(ditherAmount > 0);
	if (ditherAmount == 1)
		return;	// There's nothing to do.
	// ditherAmount is the number of distinct values we want to be adding
	// to our bitmap. We want these values to range between zero and
	// ditherAmount - 1, so we subtract one here.
	ditherAmount -= 1;

	int NumChannels = GetChannels(pBitmap);
	// Before we do the dithering we have to get the values into the right
	// range. We then have to subtract off ditherAmount / 2 which is half of
	// the maximum value so that the values are centered about zero.
	for (int y = 0; y < DITHERSIZE; y++)
	{
		for (int x = 0; x < DITHERSIZE; x++)
		{
			int Temp  = (DitherArray[y][x] * ditherAmount + 127) / 255;
			assert(Temp >= 0 && Temp <= ditherAmount);
			DitherArray[y][x] = Temp - ditherAmount / 2;
		}
	}

	// Now we can dither our image.
	for (int y = 0; y < GetHeight(pBitmap); y++)
	{
		unsigned char* pLine = GetLinePtr(pBitmap, y);
		int* pDitherLine = DitherArray[y & (DITHERSIZE - 1)];
		for (int x = 0; x < GetWidth(pBitmap); x++)
		{
			int DitherAmount = pDitherLine[x & (DITHERSIZE - 1)];
			for (int channels = 0; channels < NumChannels; channels++)
			{
				int DitheredPixel = (int)pLine[channels] + DitherAmount;
				if (DitheredPixel < 0)
					DitheredPixel = 0;
				if (DitheredPixel > 255)
					DitheredPixel = 255;
				pLine[channels] = DitheredPixel;
			}
			pLine += NumChannels;
		}
	}
}
Esempio n. 5
0
static void PointScaleBitmap(CSBitmap* SourceBitmap, CSBitmap* DestBitmap)
{
	int NumChannels = GetChannels(SourceBitmap);
	assert(GetChannels(DestBitmap) == GetChannels(SourceBitmap));

	if (gScalingOptimization)
	{
		// Point sampling.
		// Pre calculated with line copy of identical lines.
		// Should probably use new[], but I'm trying to stick to C style code.
		int* SrcXBuffer = (int*)malloc(sizeof(int) * GetWidth(DestBitmap));
		int LastSourceY = -1;
		uint8_t* pLastLine = 0;
		if (!SrcXBuffer)
			return;
		for (int x = 0; x < GetWidth(DestBitmap); ++x)
		{
			int SourceX = (x * GetWidth(SourceBitmap) + GetWidth(SourceBitmap) / 2) / GetWidth(DestBitmap);
			// Make darned sure our input coordinates are valid.
			assert(SourceX >= 0 && SourceX < GetWidth(SourceBitmap));
			SrcXBuffer[x] = SourceX * NumChannels;
		}
		// Loop over all destination lines.
		for (int y = 0; y < GetHeight(DestBitmap); ++y)
		{
			// I don't bother optimizing the outer loop.
			// Calculate the line number we want to read from.
			int SourceY = (y * GetHeight(SourceBitmap) + GetHeight(SourceBitmap) / 2) / GetHeight(DestBitmap);
			// Get the destination line pointer.
			uint8_t* pDestLine = GetLinePtr(DestBitmap, y);
			if (SourceY == LastSourceY)
			{
				// If we're still reading from the same source line then the results
				// are going to be identical - so just copy them over.
				memcpy(pDestLine, pLastLine, GetWidth(DestBitmap) * NumChannels);
			}
			else
			{
				uint8_t* pSourceLine = GetLinePtr(SourceBitmap, SourceY);
				// We must update pLastLine before the x-loop because the x-loop
				// modifies it.
				pLastLine = pDestLine;
				LastSourceY = SourceY;
				// For each pixel in the line...
				for (int x = 0; x < GetWidth(DestBitmap); ++x)
				{
					// Calculate the address of the pixel we want to read from.
					uint8_t* pSourcePixel = pSourceLine + SrcXBuffer[x];
					// Use a switch statement instead of a loop to copy one to four bytes.
					// Notice the missing break statements so that it will fall through.
					switch (NumChannels)
					{
						case 4:
							pDestLine[3] = pSourcePixel[3];
						case 3:
							pDestLine[2] = pSourcePixel[2];
						case 2:
							pDestLine[1] = pSourcePixel[1];
						case 1:
							pDestLine[0] = pSourcePixel[0];
					}
					// Update our destination pointer to the next pixel.
					pDestLine += NumChannels;
				}
			}
		}
		free(SrcXBuffer);
	}
	else
	{
		// Point sampling.
		// Simplest implementation - no optimizations.
		// Loop over all destination lines.
		const unsigned int sWidth = GetWidth(SourceBitmap);
		const unsigned int sWidthDiv2 = sWidth / 2;
		const unsigned int dWidth = GetWidth(DestBitmap);
		for (int y = 0; y < GetHeight(DestBitmap); ++y)
		{
			// Calculate the line number we want to read from.
			int SourceY = (y * GetHeight(SourceBitmap) + GetHeight(SourceBitmap) / 2) / GetHeight(DestBitmap);
			// We don't need asserts here because GetLinePtr() will check the y-coordinate.
			// Get the source and destination line pointers.
			uint8_t* pDestLine = GetLinePtr(DestBitmap, y);
			uint8_t* pSourceLine = GetLinePtr(SourceBitmap, SourceY);
			// For each pixel in the line...
			for (unsigned int x = 0; x < dWidth; ++x)
			{
				// Calculate the column we want to read from.
				int SourceX = (x * sWidth + sWidthDiv2) / dWidth;
				// Make sure SourceX is in valid range.
				assert(SourceX >= 0 && SourceX < GetWidth(SourceBitmap));
				// And loop over all of the bytes in that pixel.
				uint8_t* pSourcePixel = pSourceLine + SourceX * NumChannels;
				for (int channel = 0; channel < NumChannels; ++channel)
					pDestLine[channel] = pSourcePixel[channel];
				pDestLine += NumChannels;
			}
		}
	}
}
Esempio n. 6
0
static void FilterScaleBitmap(CSBitmap* SourceBitmap, CSBitmap* DestBitmap)
{
	const int NumSourceChannels = GetChannels(SourceBitmap);
	int NumSourceSkipChannels = NumSourceChannels;
	const int NumDestChannels = GetChannels(DestBitmap);
	const int kNumFilterChannels = 3;	// Number of channels to filter.
	// Bilinear filtering.
	// Simple floating point code, with precalculated x-locations.
	double YRatio = GetHeight(SourceBitmap) / (double)GetHeight(DestBitmap);
	double XRatio = GetWidth(SourceBitmap) / (double)GetWidth(DestBitmap);

	RGBQUAD	paletteRGBQUAD[256];
	uint8_t	bytePalette[256 * kNumFilterChannels];
	if (NumSourceChannels == 1)
	{
		GetPalette(SourceBitmap, 0, 256, paletteRGBQUAD);
		NumSourceSkipChannels = kNumFilterChannels;
		// After getting the palette, copy it into a layout that is guaranteed to match that
		// of pixels in a bitmap.
		for (int i = 0; i < NUMELEMENTS(paletteRGBQUAD); ++i)
		{
			bytePalette[i * kNumFilterChannels + RED_BITMAP_OFFSET] = paletteRGBQUAD[i].rgbRed;
			bytePalette[i * kNumFilterChannels + GREEN_BITMAP_OFFSET] = paletteRGBQUAD[i].rgbGreen;
			bytePalette[i * kNumFilterChannels + BLUE_BITMAP_OFFSET] = paletteRGBQUAD[i].rgbBlue;
		}
	}
	// Optimized version of filtered scaling.
	// Should probably use new[], but I'm trying to stick to C style code.
	float* SrcXBuffer = (float*)malloc(sizeof(float) * GetWidth(DestBitmap));
	if (!SrcXBuffer)
		return;
	// Precalculate the sourceX values, including left edge clipping them.
	for (int x = 0; x < GetWidth(DestBitmap); ++x)
	{
		double SourceX = (x + 0.5) * XRatio;
		assert(SourceX >= 0 && SourceX < GetWidth(SourceBitmap));
		SourceX -= 0.5;	// Adjust into a more convenient range. Now represents
		// the left edge of the pixel.
		// Deal with the unfortunate border cases. We are clamping the pixels.
		// Other possibilities include wrapping, or using a border colour.
		if (SourceX < 0)
			SourceX = 0;
		if (SourceX >= GetWidth(SourceBitmap) - 1)
			SourceX = GetWidth(SourceBitmap) - 1;
		SrcXBuffer[x] = (float)SourceX;
	}
	for (int y = 0; y < GetHeight(DestBitmap); ++y)
	{
		double SourceY = (y + 0.5) * YRatio;
		assert(SourceY >= 0 && SourceY < GetHeight(SourceBitmap));
		SourceY -= 0.5;	// Adjust into a more convenient range. Now represents
		// the left edge of the pixel.
		// Deal with the unfortunate border cases. We are clamping the pixels.
		// Other possibilities include wrapping, or using a border colour.
		if (SourceY < 0)
			SourceY = 0;
		if (SourceY > GetHeight(SourceBitmap) - 1)
			SourceY = GetHeight(SourceBitmap) - 1;
		// If SourceY might be negative you have to use floor() instead of just casting to int.
		int FirstLine = (int)SourceY;
		double SecondLineWeight = SourceY - FirstLine;

		// We don't need asserts here because GetLinePtr() will check the y-coordinate.
		uint8_t* pDestLine = GetLinePtr(DestBitmap, y);
		uint8_t* pSourceLine1 = GetLinePtr(SourceBitmap, FirstLine);
		// Make sure we don't try getting the address of a non-existent line.
		// Make sure this always gets initialized to something.
		uint8_t* pSourceLine2 = pSourceLine1;
		if (FirstLine + 1 < GetHeight(SourceBitmap))
			pSourceLine2 = GetLinePtr(SourceBitmap, FirstLine + 1);
		uint8_t* pSourcePixel1Left;	// Top line, left pixel.
		uint8_t* pSourcePixel2Left;	// Second line, left pixel.
		for (int x = 0; x < GetWidth(DestBitmap); ++x)
		{
			double SourceX = SrcXBuffer[x];
			int FirstPixel = int(SourceX);
			// Set up pointers into the bitmap or the palette, for the left sample pixels.
			if (NumSourceChannels == 1)
			{
				pSourcePixel1Left = bytePalette + pSourceLine1[FirstPixel] * kNumFilterChannels;
				pSourcePixel2Left = bytePalette + pSourceLine2[FirstPixel] * kNumFilterChannels;
			}
			else
			{
				pSourcePixel1Left = pSourceLine1 + FirstPixel * NumSourceChannels;
				pSourcePixel2Left = pSourceLine2 + FirstPixel * NumSourceChannels;
			}
			uint8_t* pSourcePixel1Right;	// Top line, right pixel.
			uint8_t* pSourcePixel2Right;	// Second line, right pixel.
			// Now setup pointers into the bitmap or the palette, for the right
			// sample pixels. If there are no right sample pixels (right edge)
			// then point at the left sample pixels.
			if (SourceX >= GetWidth(SourceBitmap) - 1)
			{
				pSourcePixel1Right = pSourcePixel1Left;
				pSourcePixel2Right = pSourcePixel2Left;
			}
			else
			{
				if (NumSourceChannels == 1)
				{
					pSourcePixel1Right = bytePalette + pSourceLine1[FirstPixel+1] * kNumFilterChannels;
					pSourcePixel2Right = bytePalette + pSourceLine2[FirstPixel+1] * kNumFilterChannels;
				}
				else
				{
					pSourcePixel1Right = pSourcePixel1Left + NumSourceChannels;
					pSourcePixel2Right = pSourcePixel2Left + NumSourceChannels;
				}
			}
			double SecondPixelWeight = SourceX - FirstPixel;
			for (int channel = 0; channel < kNumFilterChannels; ++channel)
			{
				double FirstLine = pSourcePixel1Left[channel] + (pSourcePixel1Right[channel] - pSourcePixel1Left[channel]) * SecondPixelWeight;
				double SecondLine = pSourcePixel2Left[channel] + (pSourcePixel2Right[channel] - pSourcePixel2Left[channel]) * SecondPixelWeight;
				pDestLine[channel] = (uint8_t)(FirstLine + (SecondLine - FirstLine) * SecondLineWeight);
			}
			pDestLine += NumDestChannels;
		}
	}
	free(SrcXBuffer);
}