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