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
}