Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonz/Naa2TlvConverter.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonz/tcenterlinevectorizer.h"
Toshihiro Shimizu 890ddd
#include "toonz/stage.h"
Toshihiro Shimizu 890ddd
#include "tpixelutils.h"
Toshihiro Shimizu 890ddd
#include "tpalette.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <qset></qset>
Toshihiro Shimizu 890ddd
#include <qtime></qtime>
Toshihiro Shimizu 890ddd
#include <qdebug></qdebug>
Toshihiro Shimizu 890ddd
#include <qmultimap></qmultimap>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QString RegionInfo::getTypeString() const {
Shinya Kitaoka 120a6e
  switch (type) {
Shinya Kitaoka 120a6e
  case RegionInfo::Background:
Shinya Kitaoka 120a6e
    return "Background";
Shinya Kitaoka 120a6e
  case RegionInfo::Ink:
Shinya Kitaoka 120a6e
    return "Ink";
Shinya Kitaoka 120a6e
  case RegionInfo::ThinInk:
Shinya Kitaoka 120a6e
    return "ThinInk";
Shinya Kitaoka 120a6e
  case RegionInfo::MainInk:
Shinya Kitaoka 120a6e
    return "Main ink";
Shinya Kitaoka 120a6e
  case RegionInfo::SyntheticInk:
Shinya Kitaoka 120a6e
    return "SyntheticInk";
Shinya Kitaoka 120a6e
  case RegionInfo::Paint:
Shinya Kitaoka 120a6e
    return "Paint";
Shinya Kitaoka 120a6e
  case RegionInfo::LargePaint:
Shinya Kitaoka 120a6e
    return "LargePaint";
Shinya Kitaoka 120a6e
  case RegionInfo::SmallPaint:
Shinya Kitaoka 120a6e
    return "SmallPaint";
Shinya Kitaoka 120a6e
  case RegionInfo::Unused:
Shinya Kitaoka 120a6e
    return "Unused";
Shinya Kitaoka 120a6e
  case RegionInfo::Unknown:
Shinya Kitaoka 120a6e
    return "Unknown";
Shinya Kitaoka 120a6e
  default:
Shinya Kitaoka 120a6e
    return "??????";
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Naa2TlvConverter::Naa2TlvConverter()
Shinya Kitaoka 120a6e
    : MaxColorCount(1000)
Shinya Kitaoka 120a6e
    , m_regionRas(0)
Shinya Kitaoka 120a6e
    , m_borderRas(0)
Shinya Kitaoka 120a6e
    , m_dotRas(0)
Shinya Kitaoka 120a6e
    , m_syntheticInkRas(0)
Shinya Kitaoka 120a6e
    , m_inkThickness(0)
Shinya Kitaoka 120a6e
    , m_palette(0)
Shinya Kitaoka 120a6e
    , m_valid(false)
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
{}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
Naa2TlvConverter::~Naa2TlvConverter() {
Shinya Kitaoka 120a6e
  delete m_regionRas;
Shinya Kitaoka 120a6e
  delete m_borderRas;
Shinya Kitaoka 120a6e
  delete m_dotRas;
Shinya Kitaoka 120a6e
  delete m_syntheticInkRas;
Shinya Kitaoka 120a6e
  if (m_palette) m_palette->release();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Naa2TlvConverter::setPalette(TPalette *palette) {
Shinya Kitaoka 120a6e
  if (m_palette != palette) {
Shinya Kitaoka 120a6e
    if (palette) palette->addRef();
Shinya Kitaoka 120a6e
    if (m_palette) m_palette->release();
Shinya Kitaoka 120a6e
    m_palette = palette;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Naa2TlvConverter::process(const TRaster32P &srcRas) {
Shinya Kitaoka 120a6e
  m_valid = false;
Shinya Kitaoka 120a6e
  setSourceImage(srcRas);
Shinya Kitaoka 120a6e
  if (!m_valid) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  separateRegions();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  computeLinks();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  findRegionBorders();
Shinya Kitaoka 120a6e
  erodeRegions();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  findLargePaints();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  findBackgroundRegions();
Shinya Kitaoka 120a6e
  findMainInks();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // computeMainInkThickness();
Shinya Kitaoka 120a6e
  findThinInks();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  measureThickness();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // findPaints();
Shinya Kitaoka 120a6e
  findPaints2();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  findThinPaints();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  findSuspectInks();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  addBorderInks();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Input: srcRas (full color image)
Toshihiro Shimizu 890ddd
// Output:
Toshihiro Shimizu 890ddd
//   m_regionRas : pixel => region index
Toshihiro Shimizu 890ddd
//   m_regions   : region index => RegionInfo
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// Note: delete m_borderRas
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Naa2TlvConverter::setSourceImage(const TRaster32P &srcRas) {
Shinya Kitaoka 120a6e
  int lx = srcRas->getSize().lx;
Shinya Kitaoka 120a6e
  int ly = srcRas->getSize().ly;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_colors.clear();
Shinya Kitaoka 120a6e
  m_regions.clear();
Shinya Kitaoka 120a6e
  delete m_regionRas;
Shinya Kitaoka 120a6e
  m_regionRas = new WorkRaster<unsigned short="">(lx, ly);</unsigned>
Shinya Kitaoka 120a6e
  delete m_borderRas;
Shinya Kitaoka 120a6e
  m_borderRas = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  delete m_dotRas;
Shinya Kitaoka 120a6e
  m_dotRas = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  delete m_syntheticInkRas;
Shinya Kitaoka 120a6e
  m_syntheticInkRas = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QMap<tpixel32, int=""> colorTable;</tpixel32,>
Shinya Kitaoka 120a6e
  for (int y = 0; y < ly; y++) {
Shinya Kitaoka 120a6e
    TPixel32 *srcScanLine          = srcRas->pixels(y);
Shinya Kitaoka 120a6e
    unsigned short *regionScanLine = m_regionRas->pixels(y);
Shinya Kitaoka 120a6e
    for (int x = 0; x < lx; x++) {
Shinya Kitaoka 120a6e
      TPixel32 srcPix = overPixOnWhite(srcScanLine[x]);
Shinya Kitaoka 120a6e
      QMap<tpixel32, int="">::ConstIterator it = colorTable.find(srcPix);</tpixel32,>
Shinya Kitaoka 120a6e
      if (it == colorTable.end()) {
Shinya Kitaoka 120a6e
        // found new color (and therefore new region)
Shinya Kitaoka 120a6e
        RegionInfo r;
Shinya Kitaoka 120a6e
        // add new color
Shinya Kitaoka 120a6e
        r.colorIndex = m_colors.count();
Shinya Kitaoka 120a6e
        m_colors.append(srcPix);
Shinya Kitaoka 120a6e
        r.pixelCount = 1;
Shinya Kitaoka 120a6e
        // add new region
Shinya Kitaoka 120a6e
        int regionIndex = m_regions.count();
Shinya Kitaoka 120a6e
        m_regions.append(r);
Shinya Kitaoka 120a6e
        // update raster and colorTable
Shinya Kitaoka 120a6e
        regionScanLine[x] = regionIndex;
Shinya Kitaoka 120a6e
        colorTable.insert(srcPix, regionIndex);
Shinya Kitaoka 120a6e
        if (m_colors.count() > MaxColorCount) {
Shinya Kitaoka 120a6e
          return;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        // already defined color
Shinya Kitaoka 120a6e
        int regionIndex   = it.value();
Shinya Kitaoka 120a6e
        regionScanLine[x] = regionIndex;
Shinya Kitaoka 120a6e
        m_regions[regionIndex].pixelCount++;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_valid = true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// color-based regions => connection-based regions  (i.e. split unconnected
Shinya Kitaoka 120a6e
// region parts)
Toshihiro Shimizu 890ddd
// note: rebuild m_regions
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Naa2TlvConverter::separateRegions() {
Shinya Kitaoka 120a6e
  if (!m_regionRas) return;
Shinya Kitaoka 120a6e
  const int lx   = m_regionRas->getLx();
Shinya Kitaoka 120a6e
  const int ly   = m_regionRas->getLy();
Shinya Kitaoka 120a6e
  const int wrap = lx;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // we assume that m_regions contains almost no information (except:
Shinya Kitaoka 120a6e
  // m_regions[i].colorIndex == i)
Shinya Kitaoka 120a6e
  m_regions.clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  WorkRaster<int> wb(lx, ly);  // work buffer</int>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QVector<int> regionMap;  // wb pixels => region indices</int>
Shinya Kitaoka 120a6e
  QList<int> freeRegions;</int>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int y = 0; y < ly; y++) {
Shinya Kitaoka 120a6e
    unsigned short *waScanLine = m_regionRas->pixels(y);
Shinya Kitaoka 120a6e
    int *wbScanLine            = wb.pixels(y);
Shinya Kitaoka 120a6e
    for (int x = 0; x < lx; x++) {
Shinya Kitaoka 120a6e
      int c       = waScanLine[x];
Shinya Kitaoka 120a6e
      int cUp     = y > 0 ? waScanLine[x - wrap] : -1;
Shinya Kitaoka 120a6e
      int cLeft   = x > 0 ? waScanLine[x - 1] : -1;
Shinya Kitaoka 120a6e
      int cUpLeft = x > 0 && y > 0 ? waScanLine[x - wrap - 1] : -1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (c != cUp && c != cLeft && c != cUpLeft) {
Shinya Kitaoka 120a6e
        // no connection: create a new region
Shinya Kitaoka 120a6e
        Q_ASSERT(0 <= c && c < m_colors.count());
Shinya Kitaoka 120a6e
        RegionInfo region;
Shinya Kitaoka 120a6e
        region.colorIndex = c;
Shinya Kitaoka 120a6e
        int regionIndex;
Shinya Kitaoka 120a6e
        if (!freeRegions.empty()) {
Shinya Kitaoka 120a6e
          // use a previously discarded region
Shinya Kitaoka 120a6e
          regionIndex = freeRegions.back();
Shinya Kitaoka 120a6e
          freeRegions.pop_back();
Shinya Kitaoka 120a6e
          m_regions[regionIndex] = region;
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          // create a new region
Shinya Kitaoka 120a6e
          regionIndex = m_regions.count();
Shinya Kitaoka 120a6e
          m_regions.append(region);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        wbScanLine[x] = regionMap.count();
Shinya Kitaoka 120a6e
        regionMap.append(regionIndex);
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        // at least one connection
Shinya Kitaoka 120a6e
        if (c == cUpLeft)
Shinya Kitaoka 120a6e
          wbScanLine[x] = wbScanLine[x - wrap - 1];
Shinya Kitaoka 120a6e
        else if (c == cUp)
Shinya Kitaoka 120a6e
          wbScanLine[x] = wbScanLine[x - wrap];
Shinya Kitaoka 120a6e
        else {
Shinya Kitaoka 120a6e
          Q_ASSERT(c == cLeft);
Shinya Kitaoka 120a6e
          wbScanLine[x] = wbScanLine[x - 1];
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // merge if needed
Shinya Kitaoka 120a6e
      if (cUp == cLeft && cUp >= 0 &&
Shinya Kitaoka 120a6e
          regionMap[wbScanLine[x - 1]] != regionMap[wbScanLine[x - wrap]]) {
Shinya Kitaoka 120a6e
        // merge
Shinya Kitaoka 120a6e
        int pixelToDiscard = wbScanLine[x - 1];
Shinya Kitaoka 120a6e
        int pixelToKeep    = wbScanLine[x - wrap];
Shinya Kitaoka 120a6e
        Q_ASSERT(pixelToDiscard != pixelToKeep);
Shinya Kitaoka 120a6e
        int regionToDiscard = regionMap[pixelToDiscard];
Shinya Kitaoka 120a6e
        int regionToKeep    = regionMap[pixelToKeep];
Shinya Kitaoka 120a6e
        Q_ASSERT(regionToDiscard != regionToKeep);
Shinya Kitaoka 120a6e
        Q_ASSERT(m_regions[regionToDiscard].type != RegionInfo::Unused);
Shinya Kitaoka 120a6e
        Q_ASSERT(m_regions[regionToKeep].type != RegionInfo::Unused);
Shinya Kitaoka 120a6e
        for (int i = 0; i < regionMap.count(); i++)
Shinya Kitaoka 120a6e
          if (regionMap[i] == regionToDiscard) regionMap[i] = regionToKeep;
Shinya Kitaoka 120a6e
        // wbScanLine[x] = pixelToKeep;
Shinya Kitaoka 120a6e
        m_regions[regionToDiscard].type = RegionInfo::Unused;
Shinya Kitaoka 120a6e
        freeRegions.append(regionToDiscard);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // fill gaps
Shinya Kitaoka 120a6e
  for (;;) {
Shinya Kitaoka 120a6e
    // just remove topmost Unused regions
Shinya Kitaoka 120a6e
    if (!m_regions.empty() && m_regions.back().type == RegionInfo::Unused) {
Shinya Kitaoka 120a6e
      m_regions.pop_back();
Shinya Kitaoka 120a6e
      int k = m_regions.count();
Shinya Kitaoka 120a6e
      freeRegions.removeAll(k);
Shinya Kitaoka 120a6e
    } else if (!freeRegions.empty()) {
Shinya Kitaoka 120a6e
      // last region is used, but there is at least a free region with lower
Shinya Kitaoka 120a6e
      // index: move it there
Shinya Kitaoka 120a6e
      int regionToDiscard = m_regions.count() - 1;
Shinya Kitaoka 120a6e
      int regionToKeep    = freeRegions.back();
Shinya Kitaoka 120a6e
      freeRegions.pop_back();
Shinya Kitaoka 120a6e
      Q_ASSERT(m_regions[regionToKeep].type == RegionInfo::Unused);
Shinya Kitaoka 120a6e
      Q_ASSERT(m_regions[regionToDiscard].type != RegionInfo::Unused);
Shinya Kitaoka 120a6e
      Q_ASSERT(regionToKeep < regionToDiscard);
Shinya Kitaoka 120a6e
      m_regions[regionToKeep] = m_regions[regionToDiscard];
Shinya Kitaoka 120a6e
      // pop the region to discard
Shinya Kitaoka 120a6e
      m_regions.pop_back();
Shinya Kitaoka 120a6e
      // update map
Shinya Kitaoka 120a6e
      for (int i = 0; i < regionMap.count(); i++)
Shinya Kitaoka 120a6e
        if (regionMap[i] == regionToDiscard) regionMap[i] = regionToKeep;
Shinya Kitaoka 120a6e
    } else
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  Q_ASSERT(freeRegions.empty());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_regions.count(); i++) m_regions[i].pixelCount = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // wb => m_regionRas
Shinya Kitaoka 120a6e
  for (int y = 0; y < ly; y++) {
Shinya Kitaoka 120a6e
    unsigned short *regionScanLine = m_regionRas->pixels(y);
Shinya Kitaoka 120a6e
    int *wbScanLine                = wb.pixels(y);
Shinya Kitaoka 120a6e
    for (int x = 0; x < lx; x++) {
Shinya Kitaoka 120a6e
      int regionIndex   = regionMap[wbScanLine[x]];
Shinya Kitaoka 120a6e
      regionScanLine[x] = (unsigned short)regionIndex;
Shinya Kitaoka 120a6e
      m_regions[regionIndex].pixelCount++;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// compute adjacency relationships
Toshihiro Shimizu 890ddd
// update: m_regions[].links
Toshihiro Shimizu 890ddd
// outer regions are connected to the "pseudo-region" -1
Toshihiro Shimizu 890ddd
// note: check orthogonal directions only
Toshihiro Shimizu 890ddd
// compute region.perimeter
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Naa2TlvConverter::computeLinks() {
Shinya Kitaoka 120a6e
  if (!m_regionRas || m_regions.empty()) return;
Shinya Kitaoka 120a6e
  const int lx   = m_regionRas->getLx();
Shinya Kitaoka 120a6e
  const int ly   = m_regionRas->getLy();
Shinya Kitaoka 120a6e
  const int wrap = lx;
Shinya Kitaoka 120a6e
  unsigned short *waScanLine;
Shinya Kitaoka 120a6e
  int x;
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_regions.count(); i++) m_regions[i].perimeter = 0;
Shinya Kitaoka 120a6e
  for (int y = 0; y < ly; y++) {
Shinya Kitaoka 120a6e
    waScanLine = m_regionRas->pixels(y);
Shinya Kitaoka 120a6e
    for (x = 0; x < lx; x++) {
Shinya Kitaoka 120a6e
      int c     = waScanLine[x];
Shinya Kitaoka 120a6e
      int cUp   = y > 0 ? waScanLine[x - wrap] : -1;
Shinya Kitaoka 120a6e
      int cLeft = x > 0 ? waScanLine[x - 1] : -1;
Shinya Kitaoka 120a6e
      if (c != cUp) {
Shinya Kitaoka 120a6e
        m_regions[c].touchRegion(cUp);
Shinya Kitaoka 120a6e
        m_regions[c].perimeter++;
Shinya Kitaoka 120a6e
        if (cUp >= 0) {
Shinya Kitaoka 120a6e
          m_regions[cUp].touchRegion(c);
Shinya Kitaoka 120a6e
          m_regions[cUp].perimeter++;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      if (c != cLeft) {
Shinya Kitaoka 120a6e
        m_regions[c].touchRegion(cLeft);
Shinya Kitaoka 120a6e
        m_regions[c].perimeter++;
Shinya Kitaoka 120a6e
        if (cLeft >= 0) {
Shinya Kitaoka 120a6e
          m_regions[cLeft].touchRegion(c);
Shinya Kitaoka 120a6e
          m_regions[cLeft].perimeter++;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    m_regions[waScanLine[lx - 1]].touchRegion(-1);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  waScanLine = m_regionRas->pixels(ly - 1);
Shinya Kitaoka 120a6e
  for (x = 0; x < lx; x++) {
Shinya Kitaoka 120a6e
    m_regions[waScanLine[x]].touchRegion(-1);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
shun_iwasawa 22ad9e
// find background regions : (almost) white
Toshihiro Shimizu 890ddd
//
Shinya Kitaoka 120a6e
void Naa2TlvConverter::findBackgroundRegions() {
Shinya Kitaoka 120a6e
  if (!m_regionRas || m_regions.empty()) return;
Shinya Kitaoka 120a6e
  int lx = m_regionRas->getLx();
Shinya Kitaoka 120a6e
  int ly = m_regionRas->getLy();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // find the whitest color
Shinya Kitaoka 120a6e
  int bgColorIndex = -1;
Shinya Kitaoka 120a6e
  int maxV         = 0;
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_colors.count(); i++) {
Shinya Kitaoka 120a6e
    TPixel color = m_colors.at(i);
Shinya Kitaoka 120a6e
    int v        = color.r + color.g + color.b;
Shinya Kitaoka 120a6e
    int a        = qMin(color.r, qMin(color.g, color.b));
Shinya Kitaoka 120a6e
    if (a < 230) continue;
Shinya Kitaoka 120a6e
    if (v > maxV) {
Shinya Kitaoka 120a6e
      bgColorIndex = i;
Shinya Kitaoka 120a6e
      maxV         = v;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (bgColorIndex < 0) {
Shinya Kitaoka 120a6e
    // no white found. no bg region
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_regions.count(); i++) {
shun_iwasawa 22ad9e
    RegionInfo ®ion                                 = m_regions[i];
shun_iwasawa 22ad9e
    if (region.colorIndex == bgColorIndex) region.type = RegionInfo::Background;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// start computing m_borderRas : 1 for boundary pixels, 0 for internal pixels
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Naa2TlvConverter::findRegionBorders() {
Shinya Kitaoka 120a6e
  if (!m_regionRas) return;
Shinya Kitaoka 120a6e
  int lx = m_regionRas->getLx();
Shinya Kitaoka 120a6e
  int ly = m_regionRas->getLy();
Shinya Kitaoka 120a6e
  delete m_borderRas;
Shinya Kitaoka 120a6e
  m_borderRas = new WorkRaster<unsigned char="">(lx, ly);</unsigned>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  static const int dd[][2] = {{-1, -1}, {0, -1}, {1, -1}, {-1, 0},
Shinya Kitaoka 120a6e
                              {1, 0},   {-1, 1}, {0, 1},  {1, 1}};
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // find region-region boundaries
Shinya Kitaoka 120a6e
  for (int y = 0; y < ly; y++) {
Shinya Kitaoka 120a6e
    unsigned short *workScanLine  = m_regionRas->pixels(y);
Shinya Kitaoka 120a6e
    unsigned char *borderScanLine = m_borderRas->pixels(y);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (int x = 0; x < lx; x++) {
Shinya Kitaoka 120a6e
      int k = workScanLine[x];
Shinya Kitaoka 120a6e
      Q_ASSERT(0 <= k && k < m_regions.count());
Shinya Kitaoka 120a6e
      int isBoundary = 0;
Shinya Kitaoka 120a6e
      for (int j = 0; j < 8; j++) {
Shinya Kitaoka 120a6e
        int x1 = x + dd[j][0], y1 = y + dd[j][1];
Shinya Kitaoka 120a6e
        if (0 <= x1 && x1 < lx && 0 <= y1 && y1 < ly) {
Shinya Kitaoka 120a6e
          int k1 = m_regionRas->pixels(y1)[x1];
Shinya Kitaoka 120a6e
          if (k1 != k) {
Shinya Kitaoka 120a6e
            isBoundary = 1;
Shinya Kitaoka 120a6e
            break;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      borderScanLine[x] = isBoundary;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// update m_borders, adding 2,3... for internal pixels close to boundary
Shinya Kitaoka 120a6e
// update m_regions[i].boundaries (histogram : boundaries[k] is the number of
Shinya Kitaoka 120a6e
// pixels belonging to that region with m_border[pix] == k)
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void Naa2TlvConverter::erodeRegions() {
Shinya Kitaoka 120a6e
  QTime clock;
Shinya Kitaoka 120a6e
  clock.start();
Shinya Kitaoka 120a6e
  if (!m_regionRas || !m_borderRas) return;
Shinya Kitaoka 120a6e
  int lx = m_regionRas->getLx();
Shinya Kitaoka 120a6e
  int ly = m_regionRas->getLy();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  static const int dd[][2] = {{-1, -1}, {0, -1}, {1, -1}, {-1, 0},
Shinya Kitaoka 120a6e
                              {1, 0},   {-1, 1}, {0, 1},  {1, 1}};
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int iter = 0; iter < 10; iter++) {
Shinya Kitaoka 120a6e
    for (int y = 0; y < ly; y++) {
Shinya Kitaoka 120a6e
      unsigned short *workScanLine  = m_regionRas->pixels(y);
Shinya Kitaoka 120a6e
      unsigned char *borderScanLine = m_borderRas->pixels(y);
Shinya Kitaoka 120a6e
      for (int x = 0; x < lx; x++) {
Shinya Kitaoka 120a6e
        if (borderScanLine[x] != iter + 1) continue;
Shinya Kitaoka 120a6e
        int c = workScanLine[x];
Shinya Kitaoka 120a6e
        for (int j = 0; j < 8; j++) {
Shinya Kitaoka 120a6e
          int x1 = x + dd[j][0], y1 = y + dd[j][1];
Shinya Kitaoka 120a6e
          if (!(0 <= x1 && x1 < lx && 0 <= y1 && y1 < ly)) continue;
Shinya Kitaoka 120a6e
          int c1 = m_regionRas->pixels(y1)[x1];
Shinya Kitaoka 120a6e
          int b1 = m_borderRas->pixels(y1)[x1];
Shinya Kitaoka 120a6e
          if (c1 == c && b1 == 0) m_borderRas->pixels(y1)[x1] = iter + 2;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_regions.count(); i++) m_regions[i].boundaries.clear();
Shinya Kitaoka 120a6e
  for (int y = 0; y < ly; y++) {
Shinya Kitaoka 120a6e
    unsigned short *workScanLine  = m_regionRas->pixels(y);
Shinya Kitaoka 120a6e
    unsigned char *borderScanLine = m_borderRas->pixels(y);
Shinya Kitaoka 120a6e
    for (int x = 0; x < lx; x++) {
Shinya Kitaoka 120a6e
      int c          = workScanLine[x];
Shinya Kitaoka 120a6e
      int b          = borderScanLine[x];
Shinya Kitaoka 120a6e
      RegionInfo &r  = m_regions[c];
Shinya Kitaoka 120a6e
      QList<int> &bs = r.boundaries;</int>
Shinya Kitaoka 120a6e
      while (bs.count() <= b) bs.append(0);
Shinya Kitaoka 120a6e
      bs[b]++;
Shinya Kitaoka 120a6e
      if (b == bs.count() - 1) r.pos = QPoint(x, y);
Shinya Kitaoka 120a6e
      if (r.x0 > r.x1) {
Shinya Kitaoka 120a6e
        r.x0 = r.x1 = x;
Shinya Kitaoka 120a6e
        r.y0 = r.y1 = y;
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        if (x < r.x0)
Shinya Kitaoka 120a6e
          r.x0 = x;
Shinya Kitaoka 120a6e
        else if (x > r.x1)
Shinya Kitaoka 120a6e
          r.x1 = x;
Shinya Kitaoka 120a6e
        if (y < r.y0)
Shinya Kitaoka 120a6e
          r.y0 = y;
Shinya Kitaoka 120a6e
        else if (y > r.y1)
Shinya Kitaoka 120a6e
          r.y1 = y;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  qDebug() << "Erode regions. time = " << clock.elapsed();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// main inks touch background regions and don't have large interior
Shinya Kitaoka 120a6e
void Naa2TlvConverter::findMainInks() {
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_regions.count(); i++) {
Shinya Kitaoka 120a6e
    RegionInfo ®ion = m_regions[i];
Shinya Kitaoka 120a6e
    if (region.type != RegionInfo::Unknown) continue;
Shinya Kitaoka 120a6e
    if (region.isBackground() || region.type == RegionInfo::LargePaint ||
Shinya Kitaoka 120a6e
        region.boundaries[0] > 0)
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    double ap2 =
Shinya Kitaoka 120a6e
        100000.0 * (double)region.pixelCount / pow((double)region.perimeter, 2);
Shinya Kitaoka 120a6e
    if (ap2 > 100) continue;
Shinya Kitaoka 120a6e
    foreach (int c, region.links.keys()) {
Shinya Kitaoka 120a6e
      if (c >= 0 && (m_regions[c].isBackground() ||
Shinya Kitaoka 120a6e
                     m_regions[c].type == RegionInfo::LargePaint)) {
Shinya Kitaoka 120a6e
        int strength = region.links[c];
Shinya Kitaoka 120a6e
        if (strength > 50) {
Shinya Kitaoka 120a6e
          m_regions[i].type = RegionInfo::MainInk;
Shinya Kitaoka 120a6e
          break;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// compute the average thickness of the main ink region
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Naa2TlvConverter::computeMainInkThickness() {
Shinya Kitaoka 120a6e
  m_inkThickness  = 0.0;
Shinya Kitaoka 120a6e
  int largestArea = 0;
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_regions.count(); i++) {
Shinya Kitaoka 120a6e
    if (m_regions[i].type != RegionInfo::MainInk) continue;
Shinya Kitaoka 120a6e
    if (m_regions[i].pixelCount < largestArea) continue;
Shinya Kitaoka 120a6e
    largestArea = m_regions[i].pixelCount;
Shinya Kitaoka 120a6e
    if (i == 55) {
Shinya Kitaoka 120a6e
      int x = 123;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    QList<int> &bs = m_regions[i].boundaries;</int>
Shinya Kitaoka 120a6e
    Q_ASSERT(bs[1] > 0);
Shinya Kitaoka 120a6e
    int perimeter = m_regions[i].perimeter;
Shinya Kitaoka 120a6e
    int area      = bs[1];
Shinya Kitaoka 120a6e
    for (int j = 2; j < bs.count() && bs[j] * 2 > bs[1]; j++) area += bs[j];
Shinya Kitaoka 120a6e
    if (perimeter > 0) {
Shinya Kitaoka 120a6e
      m_inkThickness = 2 * (double)area / (double)perimeter;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Naa2TlvConverter::findLargePaints() {
Shinya Kitaoka 120a6e
  if (!m_regionRas || !m_borderRas || m_regions.empty()) return;
Shinya Kitaoka 120a6e
  QSet<int> largePaintColors;</int>
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_regions.count(); i++) {
Shinya Kitaoka 120a6e
    RegionInfo ®ion = m_regions[i];
Shinya Kitaoka 120a6e
    if (region.type != RegionInfo::Unknown) continue;
Shinya Kitaoka 120a6e
    QList<int> &bs = region.boundaries;</int>
Shinya Kitaoka 120a6e
    if (bs[0] > 0) {
Shinya Kitaoka 120a6e
      region.type = RegionInfo::LargePaint;
Shinya Kitaoka 120a6e
      largePaintColors.insert(region.colorIndex);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_regions.count(); i++) {
Shinya Kitaoka 120a6e
    RegionInfo ®ion = m_regions[i];
Shinya Kitaoka 120a6e
    if (region.type != RegionInfo::Unknown) continue;
Shinya Kitaoka 120a6e
    if (largePaintColors.contains(region.colorIndex))
Shinya Kitaoka 120a6e
      region.type = RegionInfo::LargePaint;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Naa2TlvConverter::findThinInks() {
Shinya Kitaoka 120a6e
  if (!m_regionRas || !m_borderRas || m_regions.empty()) return;
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_regions.count(); i++) {
Shinya Kitaoka 120a6e
    RegionInfo ®ion = m_regions[i];
Shinya Kitaoka 120a6e
    if (region.type != RegionInfo::Unknown) continue;
Shinya Kitaoka 120a6e
    QList<int> &bs = region.boundaries;</int>
Shinya Kitaoka 120a6e
    if (bs.count() == 2)
Shinya Kitaoka 120a6e
      region.type = RegionInfo::ThinInk;
Shinya Kitaoka 120a6e
    else if (bs.count() == 3) {
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
      if (bs[2] * 5 < bs[1]) region.type = RegionInfo::ThinInk;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
      int k = 1;
Shinya Kitaoka 120a6e
      int s = 0;
Shinya Kitaoka 120a6e
      while (k < bs.count() && s * 100 < region.pixelCount * 90) s += bs[k++];
Shinya Kitaoka 120a6e
      if (region.pixelCount > 100 && k <= 3)
Shinya Kitaoka 120a6e
        region.type = RegionInfo::ThinInk;  // era Ink per qualche ragione
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Naa2TlvConverter::findPaints() {
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_regions.count(); i++) {
Shinya Kitaoka 120a6e
    RegionInfo ®ion = m_regions[i];
Shinya Kitaoka 120a6e
    if (region.type != RegionInfo::Unknown) continue;
Shinya Kitaoka 120a6e
    foreach (int c, m_regions[i].links.keys()) {
Shinya Kitaoka 120a6e
      if (c >= 0 && m_regions[c].isInk()) {
Shinya Kitaoka 120a6e
        m_regions[i].type = RegionInfo::Paint;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Naa2TlvConverter::findPaints2() {
Shinya Kitaoka 120a6e
  double avThickness = 0.0;
Shinya Kitaoka 120a6e
  int m              = 0;
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_regions.count(); i++) {
Shinya Kitaoka 120a6e
    RegionInfo ®ion = m_regions[i];
Shinya Kitaoka 120a6e
    if (region.type == RegionInfo::MainInk) {
Shinya Kitaoka 120a6e
      avThickness += region.thickness * region.pixelCount;
Shinya Kitaoka 120a6e
      m += region.pixelCount;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (m > 0) {
Shinya Kitaoka 120a6e
    avThickness = avThickness / m;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    avThickness = 1.5;  // this should never happen
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_regions.count(); i++) {
Shinya Kitaoka 120a6e
    RegionInfo ®ion = m_regions[i];
Shinya Kitaoka 120a6e
    if (region.type != RegionInfo::Unknown) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (region.thickness > 0.0) {
Shinya Kitaoka 120a6e
      if (region.thickness < 1.2 * avThickness)
Shinya Kitaoka 120a6e
        region.type = RegionInfo::Ink;
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        region.type = RegionInfo::Paint;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Naa2TlvConverter::findThinPaints() {
Shinya Kitaoka 120a6e
  int lx = m_regionRas->getLx();
Shinya Kitaoka 120a6e
  int ly = m_regionRas->getLy();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QList<int> regions;</int>
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_regions.count(); i++) {
Shinya Kitaoka 120a6e
    RegionInfo ®ion = m_regions[i];
Shinya Kitaoka 120a6e
    if (!region.isInk()) continue;
Shinya Kitaoka 120a6e
    if (region.type == RegionInfo::MainInk) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    int inkBoundary = 0;
Shinya Kitaoka 120a6e
    QMap<int, int="">::ConstIterator it;</int,>
Shinya Kitaoka 120a6e
    for (it = region.links.begin(); it != region.links.end(); ++it) {
Shinya Kitaoka 120a6e
      int c            = it.key();
Shinya Kitaoka 120a6e
      int linkStrength = it.value();  // number of contact points
Shinya Kitaoka 120a6e
      if (c >= 0 && m_regions[c].isInk()) inkBoundary += linkStrength;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    region.inkBoundary = inkBoundary;
Shinya Kitaoka 120a6e
    if (inkBoundary * 100 > region.perimeter * 80) regions.append(i);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  foreach (int c, regions)
Shinya Kitaoka 120a6e
    m_regions[c].type = RegionInfo::SmallPaint;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Naa2TlvConverter::findSuspectInks() {
Shinya Kitaoka 120a6e
  QMultiMap<tuint32, int=""> paintColorTable;</tuint32,>
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_regions.count(); i++) {
Shinya Kitaoka 120a6e
    RegionInfo ®ion = m_regions[i];
Shinya Kitaoka 120a6e
    if (0 == (region.type & RegionInfo::Paint)) continue;
Shinya Kitaoka 120a6e
    TPixel32 color = m_colors[region.colorIndex];
Shinya Kitaoka 120a6e
    if (color == TPixel32(0, 0, 0)) {
Shinya Kitaoka 120a6e
      int x = 1234;
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    TUINT32 rawColor = *(TUINT32 *)&color;
Shinya Kitaoka 120a6e
    paintColorTable.insert(rawColor, i);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int count = 0;
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_regions.count(); i++) {
Shinya Kitaoka 120a6e
    RegionInfo ®ion = m_regions[i];
Shinya Kitaoka 120a6e
    if (region.isInk() && region.links.size() == 2) {
Shinya Kitaoka 120a6e
      int ra = region.links.keys().at(0), rb = region.links.keys().at(1);
Shinya Kitaoka 120a6e
      if (ra >= 0 && rb >= 0) {
Shinya Kitaoka 120a6e
        if (!m_regions[ra].isInk()) qSwap(ra, rb);
Shinya Kitaoka 120a6e
        if (m_regions[ra].isInk() && !m_regions[rb].isInk()) {
Shinya Kitaoka 120a6e
          int sa = region.links[ra];
Shinya Kitaoka 120a6e
          int sb = region.links[rb];
Shinya Kitaoka 120a6e
          if (sa > sb) {
Shinya Kitaoka 120a6e
            region.type = RegionInfo::Paint;
Shinya Kitaoka 120a6e
            count++;
Shinya Kitaoka 120a6e
            continue;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (region.type != RegionInfo::ThinInk) continue;
Shinya Kitaoka 120a6e
    TUINT32 rawColor = *(TUINT32 *)&m_colors[region.colorIndex];
Shinya Kitaoka 120a6e
    if (paintColorTable.contains(rawColor)) {
Shinya Kitaoka 120a6e
      region.type = RegionInfo::Unknown;
Shinya Kitaoka 120a6e
      count++;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_regions.count(); i++) {
Shinya Kitaoka 120a6e
    RegionInfo ®ion = m_regions[i];
Shinya Kitaoka 120a6e
    if (region.isInk() && 10 <= region.pixelCount && region.pixelCount < 100) {
Shinya Kitaoka 120a6e
      int lx = region.x1 - region.x0 + 1;
Shinya Kitaoka 120a6e
      int ly = region.y1 - region.y0 + 1;
Shinya Kitaoka 120a6e
      int d  = qMax(lx, ly);
Shinya Kitaoka 120a6e
      if (qMin(lx, ly) * 2 > qMax(lx, ly) && region.pixelCount > d * d / 2) {
Shinya Kitaoka 120a6e
        region.type = RegionInfo::Paint;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (region.type == RegionInfo::Paint ||
Shinya Kitaoka 120a6e
        region.type == RegionInfo::Unknown) {
Shinya Kitaoka 120a6e
      bool isInk = false;
Shinya Kitaoka 120a6e
      if (region.boundaries.at(0) == 0) {
Shinya Kitaoka 120a6e
        if (region.boundaries.count() == 2)
Shinya Kitaoka 120a6e
          isInk = true;
Shinya Kitaoka 120a6e
        else if (region.boundaries.count() == 3) {
Shinya Kitaoka 120a6e
          int b1                 = region.boundaries.at(1);
Shinya Kitaoka 120a6e
          int b2                 = region.boundaries.at(2);
Shinya Kitaoka 120a6e
          if (b1 * 2 < b2) isInk = true;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      if (isInk) region.type = RegionInfo::Ink;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Naa2TlvConverter::assignColorTypes() {
Shinya Kitaoka 120a6e
  if (!m_regionRas || !m_borderRas || m_regions.empty()) return;
Shinya Kitaoka 120a6e
  int lx = m_regionRas->getLx();
Shinya Kitaoka 120a6e
  int ly = m_regionRas->getLy();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_regions.count(); i++) {
Shinya Kitaoka 120a6e
    RegionInfo ®ion = m_regions[i];
Shinya Kitaoka 120a6e
    if (region.type != RegionInfo::Unknown) continue;
Shinya Kitaoka 120a6e
    QList<int> &bs = region.boundaries;</int>
Shinya Kitaoka 120a6e
    if (bs[0] > 0) {
Shinya Kitaoka 120a6e
      region.type = RegionInfo::LargePaint;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      int b = 0;
Shinya Kitaoka 120a6e
      for (int j = 1; j <= 2 && j < bs.count(); j++) b += bs[j];
Shinya Kitaoka 120a6e
      if (region.pixelCount > 200 &&
Shinya Kitaoka 120a6e
          (region.pixelCount - b) * 10 < region.pixelCount) {
Shinya Kitaoka 120a6e
        region.type = RegionInfo::ThinInk;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Naa2TlvConverter::addBorderInks()  // add syntethic inks: lines between two
Shinya Kitaoka 120a6e
                                        // adjacent fill-regions
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 120a6e
  int lx                   = m_regionRas->getLx();
Shinya Kitaoka 120a6e
  int ly                   = m_regionRas->getLy();
Shinya Kitaoka 120a6e
  static const int dd[][2] = {{0, -1}, {-1, 0},  {1, 0},  {0, 1},
Shinya Kitaoka 120a6e
                              {1, 1},  {-1, -1}, {-1, 1}, {1, -1}};
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_syntheticInkRas = new WorkRaster<unsigned char="">(lx, ly);</unsigned>
Shinya Kitaoka 120a6e
  for (int i = 0; i < lx * ly; i++) m_syntheticInkRas->pixels(0)[i] = 0;
Shinya Kitaoka 120a6e
shun-iwasawa 1584bb
  // calculate brightness of all colors in order to decide the region on which
shun-iwasawa 1584bb
  // the border to be added
shun-iwasawa 1584bb
  QList<int> colorsBrightness;</int>
shun-iwasawa 1584bb
  QVector<tpixel32>::iterator c;</tpixel32>
shun-iwasawa 1584bb
  for (c = m_colors.begin(); c != m_colors.end(); ++c)
shun-iwasawa 1584bb
    colorsBrightness.append((int)(*c).r * 30 + (int)(*c).g * 59 +
shun-iwasawa 1584bb
                            (int)(*c).b * 11);
shun-iwasawa 1584bb
Shinya Kitaoka 120a6e
  int borderInkColorIndex = m_colors.count();
Shinya Kitaoka 120a6e
  m_colors.append(TPixel32(255, 0, 0));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  RegionInfo borderInkRegion;
Shinya Kitaoka 120a6e
  borderInkRegion.type       = RegionInfo::SyntheticInk;
Shinya Kitaoka 120a6e
  borderInkRegion.colorIndex = borderInkColorIndex;
Shinya Kitaoka 120a6e
  int borderInkRegionIndex   = m_regions.count();
Shinya Kitaoka 120a6e
  m_regions.append(borderInkRegion);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int y = 0; y < ly; y++) {
Shinya Kitaoka 120a6e
    unsigned short *workScanLine  = m_regionRas->pixels(y);
Shinya Kitaoka 120a6e
    unsigned char *borderScanLine = m_borderRas->pixels(y);
Shinya Kitaoka 120a6e
    for (int x = 0; x < lx; x++) {
Shinya Kitaoka 120a6e
      int c = workScanLine[x];
Shinya Kitaoka 120a6e
      if (borderScanLine[x] != 1) continue;  // consider border pixel only
Shinya Kitaoka 120a6e
      if (0 == (m_regions[c].type & RegionInfo::Paint) &&
Shinya Kitaoka 120a6e
          m_regions[c].type != RegionInfo::Unknown)
Shinya Kitaoka 120a6e
        continue;  // consider paint pixels only
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // is touching a different no-ink pixel?
Shinya Kitaoka 120a6e
      bool touchesOtherRegion = false;
Shinya Kitaoka 120a6e
      for (int j = 0; j < 8; j++) {
Shinya Kitaoka 120a6e
        int x1 = x + dd[j][0], y1 = y + dd[j][1];
Shinya Kitaoka 120a6e
        if (0 <= x1 && x1 < lx && 0 <= y1 && y1 < ly) {
Shinya Kitaoka 120a6e
          int c1 = m_regionRas->pixels(y1)[x1];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          if (m_regions[c1].type == RegionInfo::Background) {
Shinya Kitaoka 120a6e
            touchesOtherRegion = true;
Shinya Kitaoka 120a6e
            break;
Shinya Kitaoka 120a6e
          } else if (m_regions[c1].type == RegionInfo::Unknown ||
Shinya Kitaoka 120a6e
                     (m_regions[c1].type & RegionInfo::Paint) != 0) {
Shinya Kitaoka 120a6e
            // OLD: note: we consider only regions with a lower index, to avoid
Shinya Kitaoka 120a6e
            // to create double border strokes
Shinya Kitaoka 120a6e
            // NEW: we put syntetic ink pixels in larger regions
shun-iwasawa 1584bb
            // UPDATE 2017/5/12 : we put ink on darker style
shun-iwasawa 1584bb
            if (colorsBrightness[m_regions[c1].colorIndex] >
shun-iwasawa 1584bb
                colorsBrightness[m_regions[c].colorIndex]) {
Shinya Kitaoka 120a6e
              touchesOtherRegion = true;
Shinya Kitaoka 120a6e
              break;
Shinya Kitaoka 120a6e
            }
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (touchesOtherRegion) {
Shinya Kitaoka 120a6e
        m_syntheticInkRas->pixels(y)[x] = 1;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Naa2TlvConverter::measureThickness() {
Shinya Kitaoka 120a6e
  QTime timer;
Shinya Kitaoka 120a6e
  timer.start();
Shinya Kitaoka 120a6e
  if (!m_regionRas || !m_borderRas) return;
Shinya Kitaoka 120a6e
  unsigned short *regionBuffer = m_regionRas->pixels();
Shinya Kitaoka 120a6e
  unsigned char *borderBuffer  = m_borderRas->pixels();
Shinya Kitaoka 120a6e
  int lx                       = m_regionRas->getLx();
Shinya Kitaoka 120a6e
  int ly                       = m_regionRas->getLy();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!m_dotRas || m_dotRas->getLx() != lx || m_dotRas->getLy() != ly) {
Shinya Kitaoka 120a6e
    delete m_dotRas;
Shinya Kitaoka 120a6e
    m_dotRas = new WorkRaster<unsigned char="">(lx, ly);</unsigned>
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  memset(m_dotRas->pixels(), 0, lx * ly);
Shinya Kitaoka 120a6e
  // for(int i=0;i<lx*ly;i++) m_dotras-="">pixels()[i]=0;</lx*ly;i++)>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  unsigned char *dotBuffer = m_dotRas->pixels();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int y = 0; y < ly; y++) {
Shinya Kitaoka 120a6e
    for (int x = 0; x < lx; x++) {
Shinya Kitaoka 120a6e
      if (borderBuffer[y * lx + x] != 1) continue;
Shinya Kitaoka 120a6e
      if (dotBuffer[y * lx + x] != 0) continue;
Shinya Kitaoka 120a6e
      int regionId       = regionBuffer[y * lx + x];
Shinya Kitaoka 120a6e
      RegionInfo ®ion = m_regions[regionId];
Shinya Kitaoka 120a6e
      int type           = region.type;
Shinya Kitaoka 120a6e
      if (type == RegionInfo::Background || type == RegionInfo::LargePaint ||
Shinya Kitaoka 120a6e
          type == RegionInfo::ThinInk)
Shinya Kitaoka 120a6e
        continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      int thickness = measureThickness(x, y);
Shinya Kitaoka 120a6e
      if (thickness < 1) continue;
Shinya Kitaoka 120a6e
      QMap<int, int="">::Iterator it = region.thicknessHistogram.find(thickness);</int,>
Shinya Kitaoka 120a6e
      if (it != region.thicknessHistogram.end())
Shinya Kitaoka 120a6e
        it.value() += 1;
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        region.thicknessHistogram.insert(thickness, 1);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_regions.count(); i++) {
Shinya Kitaoka 120a6e
    RegionInfo ®ion = m_regions[i];
Shinya Kitaoka 120a6e
    int type           = region.type;
Shinya Kitaoka 120a6e
    if (type == RegionInfo::Background || type == RegionInfo::LargePaint ||
Shinya Kitaoka 120a6e
        type == RegionInfo::ThinInk)
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    int thicknessCount = 0;
Shinya Kitaoka 120a6e
    double thickness   = 0.0;
Shinya Kitaoka 120a6e
    for (QMap<int, int="">::Iterator it = region.thicknessHistogram.begin();</int,>
Shinya Kitaoka 120a6e
         it != region.thicknessHistogram.end(); ++it) {
Shinya Kitaoka 120a6e
      thicknessCount += it.value();
Shinya Kitaoka 120a6e
      thickness += it.key() * it.value();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (thicknessCount > 0) {
Shinya Kitaoka 120a6e
      thickness *= 1.0 / thicknessCount;
Shinya Kitaoka 120a6e
      region.thickness = thickness;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  qDebug() << "measure thickness. time=" << timer.elapsed();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int Naa2TlvConverter::measureThickness(int x0, int y0) {
Shinya Kitaoka 120a6e
  if (!m_regionRas || !m_borderRas || !m_dotRas) return -1;
Shinya Kitaoka 120a6e
  unsigned short *regionBuffer = m_regionRas->pixels();
Shinya Kitaoka 120a6e
  unsigned char *borderBuffer  = m_borderRas->pixels();
Shinya Kitaoka 120a6e
  unsigned char *dotBuffer     = m_dotRas->pixels();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int lx = m_regionRas->getLx();
Shinya Kitaoka 120a6e
  int ly = m_regionRas->getLy();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int k0 = lx * y0 + x0;
Shinya Kitaoka 120a6e
  // no needs to worry about image limits
Shinya Kitaoka 120a6e
  if (x0 - 1 < 0 || x0 + 1 >= lx || y0 - 1 < 0 || y0 + 1 >= ly) return -1;
Shinya Kitaoka 120a6e
  // we must start from a border
Shinya Kitaoka 120a6e
  if (borderBuffer[k0] != 1) return -1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // far from other measures
Shinya Kitaoka 120a6e
  if (dotBuffer[k0] != 0) return -1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int regionId     = regionBuffer[k0];
Shinya Kitaoka 120a6e
  RegionInfo &info = m_regions[regionId];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // directions
Shinya Kitaoka 120a6e
  const int dd[8] = {1, lx + 1, lx, lx - 1, -1, -1 - lx, -lx, 1 - lx};
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // a is a direction index; a : inside; a+1 : outside
Shinya Kitaoka 120a6e
  int a = 0;
Shinya Kitaoka 120a6e
  while (a < 8 &&
Shinya Kitaoka 120a6e
         !(regionBuffer[k0 + dd[a]] == regionId &&
Shinya Kitaoka 120a6e
           regionBuffer[k0 + dd[(a + 1) % 8]] != regionId))
Shinya Kitaoka 120a6e
    a++;
Shinya Kitaoka 120a6e
  if (a == 8) {
Shinya Kitaoka 120a6e
    // k0 is an isolated point or (strange!) an intern point
Shinya Kitaoka 120a6e
    qDebug() << "Isolated point or intern point";
Shinya Kitaoka 120a6e
    return -1;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  int ka = k0 + dd[a];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int b                                          = (a + 2) % 8;
Shinya Kitaoka 120a6e
  while (regionBuffer[k0 + dd[b]] != regionId) b = (b + 1) % 8;
Shinya Kitaoka 120a6e
  // a..b = boundaries
Shinya Kitaoka 120a6e
  int kb = k0 + dd[b];
Shinya Kitaoka 120a6e
  if (a == b || ((b + 1) % 8) == a) return -1;  // k0 is a corner
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  dotBuffer[k0] = 1;
Shinya Kitaoka 120a6e
  dotBuffer[ka] = 2;
Shinya Kitaoka 120a6e
  dotBuffer[kb] = 3;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int c       = (b + 1) % 8;
Shinya Kitaoka 120a6e
  bool isThin = false;
Shinya Kitaoka 120a6e
  while (c != a) {
Shinya Kitaoka 120a6e
    if (regionBuffer[k0 + dd[c]] != regionId) {
Shinya Kitaoka 120a6e
      isThin = true;
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    c = (c + 1) % 8;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (isThin) {
Shinya Kitaoka 120a6e
    // stroke larga un pixel, con paint da una parte e dall'altra.
Shinya Kitaoka 120a6e
    return 1;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int baseLength = 3;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int d      = b;
Shinya Kitaoka 120a6e
  int oldk   = k0;
Shinya Kitaoka 120a6e
  int k      = kb;
Shinya Kitaoka 120a6e
  int lastd2 = 0;
Shinya Kitaoka 120a6e
  for (int i = 0; i < baseLength; i++) {
Shinya Kitaoka 120a6e
    int x = k % lx;
Shinya Kitaoka 120a6e
    int y = k / lx;
Shinya Kitaoka 120a6e
    if (x <= 1 || x >= lx - 1 || y <= 1 || y >= ly - 1)
Shinya Kitaoka 120a6e
      break;  // just to be sure
Shinya Kitaoka 120a6e
    int d2 = (x - x0) * (x - x0) + (y - y0) * (y - y0);
Shinya Kitaoka 120a6e
    if (d2 <= lastd2) break;
Shinya Kitaoka 120a6e
    lastd2                                          = d2;
Shinya Kitaoka 120a6e
    int d1                                          = (d + 4) % 8;
Shinya Kitaoka 120a6e
    d1                                              = (d1 + 1) % 8;
Shinya Kitaoka 120a6e
    while (regionBuffer[k + dd[d1]] != regionId) d1 = (d1 + 1) % 8;
Shinya Kitaoka 120a6e
    Q_ASSERT(regionBuffer[k + dd[d1]] == regionId);
Shinya Kitaoka 120a6e
    oldk         = k;
Shinya Kitaoka 120a6e
    k            = k + dd[d1];
Shinya Kitaoka 120a6e
    d            = d1;
Shinya Kitaoka 120a6e
    dotBuffer[k] = 4;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // punto ad un estremo (lungo il confine)
Shinya Kitaoka 120a6e
  int x1 = k % lx;
Shinya Kitaoka 120a6e
  int y1 = k / lx;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  d      = a;
Shinya Kitaoka 120a6e
  oldk   = k0;
Shinya Kitaoka 120a6e
  k      = ka;
Shinya Kitaoka 120a6e
  lastd2 = 0;
Shinya Kitaoka 120a6e
  for (int i = 0; i < baseLength; i++) {
Shinya Kitaoka 120a6e
    int x = k % lx;
Shinya Kitaoka 120a6e
    int y = k / lx;
Shinya Kitaoka 120a6e
    if (x <= 1 || x >= lx - 1 || y <= 1 || y >= ly - 1)
Shinya Kitaoka 120a6e
      break;  // just to be sure
Shinya Kitaoka 120a6e
    int d2 = (x - x0) * (x - x0) + (y - y0) * (y - y0);
Shinya Kitaoka 120a6e
    if (d2 <= lastd2) break;
Shinya Kitaoka 120a6e
    lastd2                                          = d2;
Shinya Kitaoka 120a6e
    int d1                                          = (d + 4) % 8;
Shinya Kitaoka 120a6e
    d1                                              = (d1 + 7) % 8;
Shinya Kitaoka 120a6e
    while (regionBuffer[k + dd[d1]] != regionId) d1 = (d1 + 7) % 8;
Shinya Kitaoka 120a6e
    Q_ASSERT(regionBuffer[k + dd[d1]] == regionId);
Shinya Kitaoka 120a6e
    oldk         = k;
Shinya Kitaoka 120a6e
    k            = k + dd[d1];
Shinya Kitaoka 120a6e
    d            = d1;
Shinya Kitaoka 120a6e
    dotBuffer[k] = 5;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // punto all'estremo opposto (lungo il confine)
Shinya Kitaoka 120a6e
  int x2 = k % lx;
Shinya Kitaoka 120a6e
  int y2 = k / lx;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int dx = y2 - y1, dy = x1 - x2;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int delta2 = dx * dx + dy * dy;
Shinya Kitaoka 120a6e
  if (delta2 < baseLength * baseLength * 3) return -1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int adx = abs(dx), ady = abs(dy);
Shinya Kitaoka 120a6e
  int sgx = dx > 0 ? 1 : -1, sgy = dy > 0 ? 1 : -1;
Shinya Kitaoka 120a6e
  int thickness          = 1;
Shinya Kitaoka 120a6e
  const int maxThickness = 64;
Shinya Kitaoka 120a6e
  for (; thickness < maxThickness; thickness++) {
Shinya Kitaoka 120a6e
    int x, y;
Shinya Kitaoka 120a6e
    if (adx > ady) {
Shinya Kitaoka 120a6e
      x = x0 + thickness * sgx;
Shinya Kitaoka 120a6e
      y = y0 + sgy * (thickness * ady + adx / 2) / adx;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      y = y0 + thickness * sgy;
Shinya Kitaoka 120a6e
      x = x0 + sgx * (thickness * adx + ady / 2) / ady;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    k = y * lx + x;
Shinya Kitaoka 120a6e
    if (0 <= x && x < lx && 0 <= y && y < ly && regionBuffer[k] == regionId)
Shinya Kitaoka 120a6e
      dotBuffer[k] = 6;
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return thickness;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
shun_iwasawa 1fa45a
TToonzImageP Naa2TlvConverter::makeTlv(bool transparentSyntheticInks,
shun-iwasawa 1584bb
                                       QList<int> &usedStyleIds, double dpi) {</int>
Shinya Kitaoka 120a6e
  if (!m_valid || m_colors.empty() || m_regions.empty() || !m_regionRas)
Shinya Kitaoka 120a6e
    return TToonzImageP();
Shinya Kitaoka 120a6e
  int lx                = m_regionRas->getLx();
Shinya Kitaoka 120a6e
  int ly                = m_regionRas->getLy();
Shinya Kitaoka 120a6e
  TPalette *palette     = m_palette;
Shinya Kitaoka 120a6e
  if (!palette) palette = new TPalette();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRasterCM32P ras(lx, ly);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QList<int> styleIds;</int>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_colors.count() - 1; i++) {
Shinya Kitaoka 120a6e
    TPixel32 color  = m_colors.at(i);
Shinya Kitaoka 120a6e
    int styleId     = palette->getClosestStyle(color);
Shinya Kitaoka 120a6e
    TColorStyle *cs = styleId < 0 ? 0 : palette->getStyle(styleId);
Shinya Kitaoka 120a6e
    if (cs) {
Shinya Kitaoka 120a6e
      if (cs->getMainColor() != color) cs = 0;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (cs == 0) {
shun_iwasawa 1fa45a
      styleId = palette->addStyle(color);
shun_iwasawa 1fa45a
      palette->getPage(0)->addStyle(styleId);
shun_iwasawa 1fa45a
      cs = palette->getStyle(styleId);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    styleIds.append(styleId);
shun_iwasawa 22ad9e
    if (!usedStyleIds.contains(styleId)) usedStyleIds.append(styleId);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  styleIds.append(0);  // syntetic ink
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // int synteticInkStyleId = palette->getPage(0)->addStyle(TPixel32(0,0,0,0));
Shinya Kitaoka 120a6e
  // styleIds.append(synteticInkStyleId);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int y = 0; y < ly; y++) {
Shinya Kitaoka 120a6e
    unsigned short *workScanLine = m_regionRas->pixels(y);
Shinya Kitaoka 120a6e
    TPixelCM32 *outScanLine      = ras->pixels(y);
Shinya Kitaoka 120a6e
    for (int x = 0; x < lx; x++) {
Shinya Kitaoka 120a6e
      int c = workScanLine[x];
Shinya Kitaoka 120a6e
      Q_ASSERT(0 <= c && c < m_regions.count());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      int color = m_regions[c].colorIndex;
Shinya Kitaoka 120a6e
      Q_ASSERT(0 <= color && color < styleIds.count());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      int styleId = styleIds.at(color);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      RegionInfo::Type type = m_regions.at(c).type;
Shinya Kitaoka 120a6e
      if (type == RegionInfo::Background)
Shinya Kitaoka 120a6e
        outScanLine[x] = TPixelCM32();
Shinya Kitaoka 120a6e
      else if (type & RegionInfo::Ink)
Shinya Kitaoka 120a6e
        outScanLine[x] = TPixelCM32(styleId, 0, 0);
Shinya Kitaoka 120a6e
      else if (m_syntheticInkRas->pixels(y)[x] == 1)
Shinya Kitaoka 120a6e
        outScanLine[x] =
shun-iwasawa 1584bb
            TPixelCM32(transparentSyntheticInks ? 0 : styleId, 0, 0);
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        outScanLine[x] = TPixelCM32(0, styleId, 255);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
shun-iwasawa 1584bb
  struct locals {
shun-iwasawa 1584bb
    static bool compare(const QPair<int, int=""> &p1, const QPair<int, int=""> &p2) {</int,></int,>
shun-iwasawa 1584bb
      return p1.second > p2.second;
shun-iwasawa 1584bb
    }
shun-iwasawa 1584bb
shun-iwasawa 1584bb
    static void addPaint(QList<qpair<int, int="">> &list, const int paintId) {</qpair<int,>
shun-iwasawa 1584bb
      if (paintId == 0) return;
shun-iwasawa 1584bb
      for (int i = 0; i < list.size(); i++)
shun-iwasawa 1584bb
        if (list[i].first == paintId) {
shun-iwasawa 1584bb
          list[i].second += 1;
shun-iwasawa 1584bb
          return;
shun-iwasawa 1584bb
        }
shun-iwasawa 1584bb
      list.append(QPair<int, int="">(paintId, 1));</int,>
shun-iwasawa 1584bb
    }
shun-iwasawa 1584bb
  };  // locals
shun-iwasawa 1584bb
shun-iwasawa 1584bb
  // Here, expand paint area under the solid ink pixel in order to prevent the
shun-iwasawa 1584bb
  // gap appears when the "Add Antialiasing" option is activated.
shun-iwasawa 1584bb
  TRasterCM32P copiedRas = ras->clone();
shun-iwasawa 1584bb
  copiedRas->lock();
shun-iwasawa 1584bb
  for (int y = 0; y < ly; y++) {
shun-iwasawa 1584bb
    TPixelCM32 *topScanLine    = copiedRas->pixels((y == 0) ? y : y - 1);
shun-iwasawa 1584bb
    TPixelCM32 *middleScanLine = copiedRas->pixels(y);
shun-iwasawa 1584bb
    TPixelCM32 *bottomScanLine = copiedRas->pixels((y == ly - 1) ? y : y + 1);
shun-iwasawa 1584bb
    TPixelCM32 *outScanLine    = ras->pixels(y);
shun-iwasawa 1584bb
    for (int x = 0; x < lx; x++) {
shun-iwasawa 1584bb
      if (!middleScanLine[x].isPureInk() || middleScanLine[x].getPaint() != 0)
shun-iwasawa 1584bb
        continue;
shun-iwasawa 1584bb
shun-iwasawa 1584bb
      int prev_x = (x == 0) ? x : x - 1;
shun-iwasawa 1584bb
      int next_x = (x == lx - 1) ? x : x + 1;
shun-iwasawa 1584bb
      QList<qpair<int, int="">> neighborPaints;</qpair<int,>
shun-iwasawa 1584bb
      locals::addPaint(neighborPaints, topScanLine[prev_x].getPaint());
shun-iwasawa 1584bb
      locals::addPaint(neighborPaints, topScanLine[x].getPaint());
shun-iwasawa 1584bb
      locals::addPaint(neighborPaints, topScanLine[next_x].getPaint());
shun-iwasawa 1584bb
      locals::addPaint(neighborPaints, middleScanLine[prev_x].getPaint());
shun-iwasawa 1584bb
      locals::addPaint(neighborPaints, middleScanLine[next_x].getPaint());
shun-iwasawa 1584bb
      locals::addPaint(neighborPaints, bottomScanLine[prev_x].getPaint());
shun-iwasawa 1584bb
      locals::addPaint(neighborPaints, bottomScanLine[x].getPaint());
shun-iwasawa 1584bb
      locals::addPaint(neighborPaints, bottomScanLine[next_x].getPaint());
shun-iwasawa 1584bb
      qSort(neighborPaints.begin(), neighborPaints.end(), locals::compare);
shun-iwasawa 1584bb
shun-iwasawa 1584bb
      if (!neighborPaints.isEmpty())
shun-iwasawa 1584bb
        outScanLine[x].setPaint(neighborPaints[0].first);
shun-iwasawa 1584bb
    }
shun-iwasawa 1584bb
  }
shun-iwasawa 1584bb
  copiedRas->unlock();
shun-iwasawa 1584bb
Shinya Kitaoka 120a6e
  TToonzImageP ti = new TToonzImage(ras, ras->getBounds());
Shinya Kitaoka 120a6e
  ti->setPalette(palette);
shun-iwasawa 1584bb
shun-iwasawa 1584bb
  if (dpi > 0.0)  // for now, accept only square pixel
shun-iwasawa 1584bb
    ti->setDpi(dpi, dpi);
shun-iwasawa 1584bb
  else
shun-iwasawa 1584bb
    ti->setDpi(72, 72);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return ti;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TVectorImageP Naa2TlvConverter::vectorize(const TToonzImageP &ti) {
Shinya Kitaoka 120a6e
  CenterlineConfiguration conf;
Shinya Kitaoka 120a6e
  if (!ti) return TVectorImageP();
Shinya Kitaoka 120a6e
  TPalette *palette = ti->getPalette();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  VectorizerCore vc;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TAffine dpiAff;
Shinya Kitaoka 120a6e
  double factor = Stage::inch;
Shinya Kitaoka 120a6e
  double dpix = factor / 72, dpiy = factor / 72;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ti->getDpi(dpix, dpiy);
Shinya Kitaoka 120a6e
  TPointD center = ti->getRaster()->getCenterD();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (dpix != 0.0 && dpiy != 0.0) dpiAff = TScale(factor / dpix, factor / dpiy);
Shinya Kitaoka 120a6e
  factor                                 = norm(dpiAff * TPointD(1, 0));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  conf.m_affine         = dpiAff * TTranslation(-center);
Shinya Kitaoka 120a6e
  conf.m_thickScale     = factor;
Shinya Kitaoka 120a6e
  conf.m_leaveUnpainted = false;
Shinya Kitaoka 120a6e
  conf.m_makeFrame      = true;
Shinya Kitaoka 120a6e
  conf.m_penalty        = 0.0;
Shinya Kitaoka 120a6e
  conf.m_despeckling    = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TImageP img(ti.getPointer());
Shinya Kitaoka 120a6e
  TVectorImageP vi = vc.vectorize(img, conf, palette);
Shinya Kitaoka 120a6e
  vi->setPalette(palette);
Shinya Kitaoka 120a6e
  return vi;
Toshihiro Shimizu 890ddd
}
shun_iwasawa 22ad9e
shun_iwasawa 22ad9e
//-----------------------------------------------------------------------------
shun_iwasawa 22ad9e
shun_iwasawa 22ad9e
void Naa2TlvConverter::removeUnusedStyles(const QList<int> &styleIds) {</int>
shun_iwasawa 22ad9e
  // Remove unused styles from input palette
shun_iwasawa 22ad9e
  if (!m_palette) return;
shun_iwasawa 22ad9e
  for (int p = m_palette->getPageCount() - 1; p >= 0; p--) {
shun_iwasawa 22ad9e
    TPalette::Page *page = m_palette->getPage(p);
shun_iwasawa 22ad9e
    for (int s = page->getStyleCount() - 1; s >= 0; s--) {
shun_iwasawa 22ad9e
      int styleId = page->getStyleId(s);
shun_iwasawa 22ad9e
      if (styleId == -1) continue;
shun_iwasawa 22ad9e
      // check if the style is used or not
shun_iwasawa 22ad9e
      if (!styleIds.contains(styleId)) page->removeStyle(s);
shun_iwasawa 22ad9e
    }
shun_iwasawa 22ad9e
    // erase empty page
shun_iwasawa 22ad9e
    if (page->getStyleCount() == 0) m_palette->erasePage(p);
shun_iwasawa 22ad9e
  }
shun_iwasawa 22ad9e
}