|
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 |
{
|
|
Toshihiro Shimizu |
890ddd |
return tmax(abs((int)a.r - b.r),
|
|
Toshihiro Shimizu |
890ddd |
abs((int)a.g - b.g),
|
|
Toshihiro Shimizu |
890ddd |
abs((int)a.b - b.b),
|
|
Toshihiro Shimizu |
890ddd |
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 |
|
|
Toshihiro Shimizu |
890ddd |
int i, end = tmin(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 |
}
|