Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "trop.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
See Alexander Reshetov's "Morphological Antialiasing" paper on Intel Labs site.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Basically, this antialiasing algorithm is based on the following ideas:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
 - Suppose that our image is just made up of flat colors. Then, a simple antialiasing
Toshihiro Shimizu 890ddd
   approach is that of assuming that the 'actual' line separating two distinct colors
Toshihiro Shimizu 890ddd
   is the polyline that passes through the midpoint of each edge of its original jaggy
Toshihiro Shimizu 890ddd
   counterpart.
Toshihiro Shimizu 890ddd
   As pixels around the border are cut through by the polyline, the area of the pixel
Toshihiro Shimizu 890ddd
   that is filled of a certain color is its weight in the output filtered pixel.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
 - The above method can be applied on each single uniform piece of a scanline, considering
Toshihiro Shimizu 890ddd
   the lines originated by the vertical extensions of its left and right edges.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
 - Of these lines, only those which lie completely on pixels adjacent to the edge are
Toshihiro Shimizu 890ddd
   considered - so that the antialiasing effect is kept only around the contours.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
This algorithm would yield a good result at what may be considered 50% softness. Implementing
Toshihiro Shimizu 890ddd
a generalized softness simply requires that the line slopes used above are modified
Toshihiro Shimizu 890ddd
accordingly (divide by 2 * softFactor).
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
template <typename pix=""></typename>
Toshihiro Shimizu 890ddd
class PixelSelector
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	typedef PIX pixel_type;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Toshihiro Shimizu 890ddd
	int m_thresh;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	PixelSelector(int thresh) : m_thresh(thresh) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool areEqual(const PIX &a, const PIX &b) const
Toshihiro Shimizu 890ddd
	{
Shinya Kitaoka 12c444
		return std::max({
Shinya Kitaoka 12c444
			abs((int)a.r - b.r),
Shinya Kitaoka 12c444
			abs((int)a.g - b.g),
Shinya Kitaoka 12c444
			abs((int)a.b - b.b),
Shinya Kitaoka 12c444
			abs((int)a.m - b.m)}) < m_thresh;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <>
Toshihiro Shimizu 890ddd
class PixelSelector<tpixelcm32></tpixelcm32>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	typedef TPixelCM32 pixel_type;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Toshihiro Shimizu 890ddd
	int m_thresh;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	PixelSelector(int thresh) : m_thresh(thresh) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool areEqual(const TPixelCM32 &a, const TPixelCM32 &b) const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return (a.getInk() == b.getInk()) && (abs(a.getTone() - b.getTone()) < m_thresh);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename pix=""></typename>
Toshihiro Shimizu 890ddd
inline void weightPix(PIX *out, const PIX *a, const PIX *b, double weightA, double weightB)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	out->r = a->r * weightA + b->r * weightB;
Toshihiro Shimizu 890ddd
	out->g = a->g * weightA + b->g * weightB;
Toshihiro Shimizu 890ddd
	out->b = a->b * weightA + b->b * weightB;
Toshihiro Shimizu 890ddd
	out->m = a->m * weightA + b->m * weightB;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <>
Toshihiro Shimizu 890ddd
inline void weightPix<tpixelcm32>(TPixelCM32 *out, const TPixelCM32 *a, const TPixelCM32 *b,</tpixelcm32>
Toshihiro Shimizu 890ddd
								  double weightA, double weightB)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	*out = TPixelCM32(
Toshihiro Shimizu 890ddd
		out->isPurePaint() ? b->getInk() : a->getInk(), a->getPaint(),
Toshihiro Shimizu 890ddd
		a->getTone() * weightA + b->getTone() * weightB);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Returns 0 if pixels to connect are on the 00-11 diagonal, 1 on the 01-10 one.
Toshihiro Shimizu 890ddd
template <typename pix,="" selector="" typename=""></typename>
Toshihiro Shimizu 890ddd
inline bool checkNeighbourHood(int x, int y, PIX *pix, int lx, int ly, int dx, int dy,
Toshihiro Shimizu 890ddd
							   const SELECTOR &sel)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int count1 = 0, count2 = 0;
Toshihiro Shimizu 890ddd
	int dx2 = 2 * dx, dy2 = 2 * dy;
Toshihiro Shimizu 890ddd
	if (y > 1) {
Toshihiro Shimizu 890ddd
		//Lower edge
Toshihiro Shimizu 890ddd
		count1 +=
Toshihiro Shimizu 890ddd
			(int)sel.areEqual(*(pix - dx), *(pix - dy2)) +
Toshihiro Shimizu 890ddd
			(int)sel.areEqual(*(pix - dx), *(pix - dy2 - dx));
Toshihiro Shimizu 890ddd
		count2 +=
Toshihiro Shimizu 890ddd
			(int)sel.areEqual(*pix, *(pix - dy2)) +
Toshihiro Shimizu 890ddd
			(int)sel.areEqual(*pix, *(pix - dy2 - dx));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (y < ly - 1) {
Toshihiro Shimizu 890ddd
		//Upper edge
Toshihiro Shimizu 890ddd
		count1 +=
Toshihiro Shimizu 890ddd
			(int)sel.areEqual(*(pix - dx), *(pix + dy)) +
Toshihiro Shimizu 890ddd
			(int)sel.areEqual(*(pix - dx), *(pix + dy - dx));
Toshihiro Shimizu 890ddd
		count2 +=
Toshihiro Shimizu 890ddd
			(int)sel.areEqual(*pix, *(pix + dy)) +
Toshihiro Shimizu 890ddd
			(int)sel.areEqual(*pix, *(pix + dy - dx));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (x > 1) {
Toshihiro Shimizu 890ddd
		//Left edge
Toshihiro Shimizu 890ddd
		count1 +=
Toshihiro Shimizu 890ddd
			(int)sel.areEqual(*(pix - dx), *(pix - dx2)) +
Toshihiro Shimizu 890ddd
			(int)sel.areEqual(*(pix - dx), *(pix - dx2 - dy));
Toshihiro Shimizu 890ddd
		count2 +=
Toshihiro Shimizu 890ddd
			(int)sel.areEqual(*pix, *(pix - dx2)) +
Toshihiro Shimizu 890ddd
			(int)sel.areEqual(*pix, *(pix - dx2 - dy));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (x < lx - 1) {
Toshihiro Shimizu 890ddd
		//Left edge
Toshihiro Shimizu 890ddd
		count1 +=
Toshihiro Shimizu 890ddd
			(int)sel.areEqual(*(pix - dx), *(pix + dx)) +
Toshihiro Shimizu 890ddd
			(int)sel.areEqual(*(pix - dx), *(pix + dx - dy));
Toshihiro Shimizu 890ddd
		count2 +=
Toshihiro Shimizu 890ddd
			(int)sel.areEqual(*pix, *(pix + dx)) +
Toshihiro Shimizu 890ddd
			(int)sel.areEqual(*pix, *(pix + dx - dy));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Connect by minority: if there are more pixels like those on the 00-11 diagonal, connect the other,
Toshihiro Shimizu 890ddd
	//and viceversa.
Toshihiro Shimizu 890ddd
	return count1 > count2;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename pix=""></typename>
Toshihiro Shimizu 890ddd
inline void filterLine(PIX *inLPix, PIX *inUPix, PIX *outLPix, PIX *outUPix,
Toshihiro Shimizu 890ddd
					   int ll, int inDl, int outLDl, int outUDl,
Toshihiro Shimizu 890ddd
					   double hStart, double slope, bool filterLower)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(hStart >= 0.0 && slope > 0.0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double h0 = hStart, h1, area;
Toshihiro Shimizu 890ddd
	double base = hStart / slope;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 12c444
	int i, end = std::min(tfloor(base), ll);
Toshihiro Shimizu 890ddd
	if (filterLower) {
Toshihiro Shimizu 890ddd
		//Filter lower line
Toshihiro Shimizu 890ddd
		for (i = 0; i < end; ++i, h0 = h1,
Toshihiro Shimizu 890ddd
			inLPix += inDl, inUPix += inDl, outLPix += outLDl) {
Toshihiro Shimizu 890ddd
			h1 = h0 - slope;
Toshihiro Shimizu 890ddd
			area = 0.5 * (h0 + h1);
Toshihiro Shimizu 890ddd
			weightPix(outLPix, outLPix, inUPix, 1.0 - area, area);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (i < ll) {
Toshihiro Shimizu 890ddd
			double remnant = base - end;
Toshihiro Shimizu 890ddd
			area = 0.5 * remnant * h0;
Toshihiro Shimizu 890ddd
			weightPix(outLPix, outLPix, inUPix, 1.0 - area, area);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		//Filter upper line
Toshihiro Shimizu 890ddd
		for (i = 0; i < end; ++i, h0 = h1,
Toshihiro Shimizu 890ddd
			inLPix += inDl, inUPix += inDl, outUPix += outUDl) {
Toshihiro Shimizu 890ddd
			h1 = h0 - slope;
Toshihiro Shimizu 890ddd
			area = 0.5 * (h0 + h1);
Toshihiro Shimizu 890ddd
			weightPix(outUPix, outUPix, inLPix, 1.0 - area, area);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (i < ll) {
Toshihiro Shimizu 890ddd
			double remnant = base - end;
Toshihiro Shimizu 890ddd
			area = 0.5 * remnant * h0;
Toshihiro Shimizu 890ddd
			weightPix(outUPix, outUPix, inLPix, 1.0 - area, area);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename pix,="" selector="" typename=""></typename>
Toshihiro Shimizu 890ddd
inline bool checkLength(int lLine, int y, int ly, int dy,
Toshihiro Shimizu 890ddd
						PIX *pixL1, PIX *pixU1, PIX *pixL2, PIX *pixU2,
Toshihiro Shimizu 890ddd
						bool uniteU, bool do1Line,
Toshihiro Shimizu 890ddd
						const SELECTOR &sel)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//1-length edges must be processed (as primary edges) only if explicitly required,
Toshihiro Shimizu 890ddd
	//and only when its associated secondary edge is of the same length.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return (lLine > 1) ||
Toshihiro Shimizu 890ddd
		   (do1Line &&
Toshihiro Shimizu 890ddd
			((uniteU && (y > 1 && !(sel.areEqual(*pixL1, *(pixL1 - dy)) && sel.areEqual(*pixL2, *(pixL2 - dy))))) ||
Toshihiro Shimizu 890ddd
			 (y < ly - 1 && !(sel.areEqual(*pixU1, *(pixU1 + dy)) && sel.areEqual(*pixU2, *(pixU2 + dy))))));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename pix,="" selector="" typename=""></typename>
Toshihiro Shimizu 890ddd
void processLine(int r, int lx, int ly,
Toshihiro Shimizu 890ddd
				 PIX *inLRow, PIX *inURow, PIX *outLRow, PIX *outURow,
Toshihiro Shimizu 890ddd
				 int inDx, int inDy, int outLDx, int outUDx,
Toshihiro Shimizu 890ddd
				 bool do1Line, double hStart, double slope,
Toshihiro Shimizu 890ddd
				 const SELECTOR &sel)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Using a 'horizontal' notation here - but the same applies in vertical too
Toshihiro Shimizu 890ddd
	++r;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//As long as we don't reach row end, process uninterrupted separation lines
Toshihiro Shimizu 890ddd
	//between colors
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	PIX *inLL = inLRow, *inLR, *inUL = inURow, *inUR;
Toshihiro Shimizu 890ddd
	PIX *inLL_1, *inUL_1, *inLR_1, *inUR_1;
Toshihiro Shimizu 890ddd
	PIX *inLEnd = inLRow + lx * inDx;
Toshihiro Shimizu 890ddd
	int x, lLine;
Toshihiro Shimizu 890ddd
	bool uniteLL, uniteUL, uniteLR, uniteUR;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Special case: a line at row start has different weights
Toshihiro Shimizu 890ddd
	if (!sel.areEqual(*inLL, *inUL)) {
Toshihiro Shimizu 890ddd
		//Look for line ends
Toshihiro Shimizu 890ddd
		for (inLR = inLL + inDx, inUR = inUL + inDx;
Toshihiro Shimizu 890ddd
			 inLR != inLEnd && sel.areEqual(*inLL, *inLR) && sel.areEqual(*inUL, *inUR);
Toshihiro Shimizu 890ddd
			 inLR += inDx, inUR += inDx)
Toshihiro Shimizu 890ddd
			;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (inLR != inLEnd) {
Toshihiro Shimizu 890ddd
			//Found a line to process
Toshihiro Shimizu 890ddd
			lLine = (inLR - inLL) / inDx;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			inLR_1 = inLR - inDx, inUR_1 = inUR - inDx;
Toshihiro Shimizu 890ddd
			x = (inLR_1 - inLRow) / inDx;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			uniteUR = sel.areEqual(*inUR_1, *inLR);
Toshihiro Shimizu 890ddd
			uniteLR = sel.areEqual(*inLR_1, *inUR);
Toshihiro Shimizu 890ddd
			if (uniteUR || uniteLR) {
Toshihiro Shimizu 890ddd
				if (uniteUR && uniteLR)
Toshihiro Shimizu 890ddd
					//Ambiguous case. Check neighborhood to find out which one must be actually united.
Toshihiro Shimizu 890ddd
					uniteUR = !checkNeighbourHood(x + 1, r, inUR, lx, ly, inDx, inDy, sel);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (checkLength(lLine, r, ly, inDy, inLR_1, inUR_1, inLR, inUR, uniteUR, do1Line, sel))
Toshihiro Shimizu 890ddd
					filterLine(inLR_1, inUR_1, outLRow + x * outLDx, outURow + x * outUDx,
Toshihiro Shimizu 890ddd
							   lLine, -inDx, -outLDx, -outUDx, hStart, slope / (lLine << 1), uniteUR);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Update lefts
Toshihiro Shimizu 890ddd
		inLL = inLR, inUL = inUR;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Search for a line start
Toshihiro Shimizu 890ddd
	for (; inLL != inLEnd && sel.areEqual(*inLL, *inUL); inLL += inDx, inUL += inDx)
Toshihiro Shimizu 890ddd
		;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	while (inLL != inLEnd) {
Toshihiro Shimizu 890ddd
		//Look for line ends
Toshihiro Shimizu 890ddd
		for (inLR = inLL + inDx, inUR = inUL + inDx;
Toshihiro Shimizu 890ddd
			 inLR != inLEnd && sel.areEqual(*inLL, *inLR) && sel.areEqual(*inUL, *inUR);
Toshihiro Shimizu 890ddd
			 inLR += inDx, inUR += inDx)
Toshihiro Shimizu 890ddd
			;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (inLR == inLEnd)
Toshihiro Shimizu 890ddd
			break; //Dealt with later
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Found a line to process
Toshihiro Shimizu 890ddd
		lLine = (inLR - inLL) / inDx;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//First, filter left to right
Toshihiro Shimizu 890ddd
		inLL_1 = inLL - inDx, inUL_1 = inUL - inDx;
Toshihiro Shimizu 890ddd
		x = (inLL - inLRow) / inDx;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		uniteUL = sel.areEqual(*inUL, *inLL_1);
Toshihiro Shimizu 890ddd
		uniteLL = sel.areEqual(*inLL, *inUL_1);
Toshihiro Shimizu 890ddd
		if (uniteUL || uniteLL) {
Toshihiro Shimizu 890ddd
			if (uniteUL && uniteLL)
Toshihiro Shimizu 890ddd
				uniteUL = checkNeighbourHood(x, r, inUL, lx, ly, inDx, inDy, sel);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (checkLength(lLine, r, ly, inDy, inLL_1, inUL_1, inLL, inUL, uniteUL, do1Line, sel))
Toshihiro Shimizu 890ddd
				filterLine(inLL, inUL, outLRow + x * outLDx, outURow + x * outUDx,
Toshihiro Shimizu 890ddd
						   lLine, inDx, outLDx, outUDx, hStart, slope / lLine, uniteUL);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Then, filter right to left
Toshihiro Shimizu 890ddd
		inLR_1 = inLR - inDx, inUR_1 = inUR - inDx;
Toshihiro Shimizu 890ddd
		x = (inLR_1 - inLRow) / inDx;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		uniteUR = sel.areEqual(*inUR_1, *inLR);
Toshihiro Shimizu 890ddd
		uniteLR = sel.areEqual(*inLR_1, *inUR);
Toshihiro Shimizu 890ddd
		if (uniteUR || uniteLR) {
Toshihiro Shimizu 890ddd
			if (uniteUR && uniteLR)
Toshihiro Shimizu 890ddd
				uniteUR = !checkNeighbourHood(x + 1, r, inUR, lx, ly, inDx, inDy, sel);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (checkLength(lLine, r, ly, inDy, inLR_1, inUR_1, inLR, inUR, uniteUR, do1Line, sel))
Toshihiro Shimizu 890ddd
				filterLine(inLR_1, inUR_1, outLRow + x * outLDx, outURow + x * outUDx,
Toshihiro Shimizu 890ddd
						   lLine, -inDx, -outLDx, -outUDx, hStart, slope / lLine, uniteUR);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Update lefts - search for a new line start
Toshihiro Shimizu 890ddd
		inLL = inLR, inUL = inUR;
Toshihiro Shimizu 890ddd
		for (; inLL != inLEnd && sel.areEqual(*inLL, *inUL); inLL += inDx, inUL += inDx)
Toshihiro Shimizu 890ddd
			;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Special case: filter the last line in the row
Toshihiro Shimizu 890ddd
	if (inLL != inLEnd) {
Toshihiro Shimizu 890ddd
		//Found a line to process
Toshihiro Shimizu 890ddd
		lLine = (inLR - inLL) / inDx;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		inLL_1 = inLL - inDx, inUL_1 = inUL - inDx;
Toshihiro Shimizu 890ddd
		x = (inLL - inLRow) / inDx;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		uniteUL = sel.areEqual(*inUL, *inLL_1);
Toshihiro Shimizu 890ddd
		uniteLL = sel.areEqual(*inLL, *inUL_1);
Toshihiro Shimizu 890ddd
		if (uniteUL || uniteLL) {
Toshihiro Shimizu 890ddd
			if (uniteUL && uniteLL)
Toshihiro Shimizu 890ddd
				uniteUL = checkNeighbourHood(x, r, inUL, lx, ly, inDx, inDy, sel);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (checkLength(lLine, r, ly, inDy, inLL_1, inUL_1, inLL, inUL, uniteUL, do1Line, sel))
Toshihiro Shimizu 890ddd
				filterLine(inLL, inUL, outLRow + x * outLDx, outURow + x * outUDx,
Toshihiro Shimizu 890ddd
						   lLine, inDx, outLDx, outUDx, hStart, slope / (lLine << 1), uniteUL);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename pix=""></typename>
Toshihiro Shimizu 890ddd
void makeAntialias(const TRasterPT<pix> &src, TRasterPT<pix> &dst, int threshold, int softness)</pix></pix>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	dst->copy(src);
Toshihiro Shimizu 890ddd
	if (softness == 0)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double slope = (50.0 / softness);
Toshihiro Shimizu 890ddd
	double hStart = 0.5; //fixed for now
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	src->lock();
Toshihiro Shimizu 890ddd
	dst->lock();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	PixelSelector<pix> sel(threshold);</pix>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//First, filter by rows
Toshihiro Shimizu 890ddd
	int x, y, lx = src->getLx(), ly = src->getLy(), lx_1 = lx - 1, ly_1 = ly - 1;
Toshihiro Shimizu 890ddd
	for (y = 0; y < ly_1; ++y) {
Toshihiro Shimizu 890ddd
		processLine(y, lx, ly,
Toshihiro Shimizu 890ddd
					src->pixels(y), src->pixels(y + 1),
Toshihiro Shimizu 890ddd
					dst->pixels(y), dst->pixels(y + 1),
Toshihiro Shimizu 890ddd
					1, src->getWrap(), 1, 1,
Toshihiro Shimizu 890ddd
					true, hStart, slope,
Toshihiro Shimizu 890ddd
					sel);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Then, go by columns
Toshihiro Shimizu 890ddd
	for (x = 0; x < lx_1; ++x) {
Toshihiro Shimizu 890ddd
		processLine(x, ly, lx,
Toshihiro Shimizu 890ddd
					src->pixels(0) + x, src->pixels(0) + x + 1,
Toshihiro Shimizu 890ddd
					dst->pixels(0) + x, dst->pixels(0) + x + 1,
Toshihiro Shimizu 890ddd
					src->getWrap(), 1, dst->getWrap(), dst->getWrap(),
Toshihiro Shimizu 890ddd
					false, hStart, slope,
Toshihiro Shimizu 890ddd
					sel);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	dst->unlock();
Toshihiro Shimizu 890ddd
	src->unlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TRop::antialias(const TRasterP &src, const TRasterP &dst, int threshold, int softness)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(src->getSize() == dst->getSize());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TRaster32P src32(src), dst32(dst);
Toshihiro Shimizu 890ddd
	if (src32 && dst32) {
Toshihiro Shimizu 890ddd
		makeAntialias<tpixel32>(src32, dst32, threshold, softness);</tpixel32>
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TRaster64P src64(src), dst64(dst);
Toshihiro Shimizu 890ddd
	if (src64 && dst64) {
Toshihiro Shimizu 890ddd
		makeAntialias<tpixel64>(src64, dst64, threshold << 8, softness);</tpixel64>
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TRasterCM32P srcCM(src), dstCM(dst);
Toshihiro Shimizu 890ddd
	if (srcCM && dstCM) {
Toshihiro Shimizu 890ddd
		makeAntialias<tpixelcm32>(srcCM, dstCM, threshold, softness);</tpixelcm32>
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(!"Source and destination rasters must be of the same type!");
Toshihiro Shimizu 890ddd
}