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
Toshihiro Shimizu 890ddd
QString RegionInfo::getTypeString() const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	switch (type) {
Toshihiro Shimizu 890ddd
	case RegionInfo::Background:
Toshihiro Shimizu 890ddd
		return "Background";
Toshihiro Shimizu 890ddd
	case RegionInfo::Ink:
Toshihiro Shimizu 890ddd
		return "Ink";
Toshihiro Shimizu 890ddd
	case RegionInfo::ThinInk:
Toshihiro Shimizu 890ddd
		return "ThinInk";
Toshihiro Shimizu 890ddd
	case RegionInfo::MainInk:
Toshihiro Shimizu 890ddd
		return "Main ink";
Toshihiro Shimizu 890ddd
	case RegionInfo::SyntheticInk:
Toshihiro Shimizu 890ddd
		return "SyntheticInk";
Toshihiro Shimizu 890ddd
	case RegionInfo::Paint:
Toshihiro Shimizu 890ddd
		return "Paint";
Toshihiro Shimizu 890ddd
	case RegionInfo::LargePaint:
Toshihiro Shimizu 890ddd
		return "LargePaint";
Toshihiro Shimizu 890ddd
	case RegionInfo::SmallPaint:
Toshihiro Shimizu 890ddd
		return "SmallPaint";
Toshihiro Shimizu 890ddd
	case RegionInfo::Unused:
Toshihiro Shimizu 890ddd
		return "Unused";
Toshihiro Shimizu 890ddd
	case RegionInfo::Unknown:
Toshihiro Shimizu 890ddd
		return "Unknown";
Toshihiro Shimizu 890ddd
	default:
Toshihiro Shimizu 890ddd
		return "??????";
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Naa2TlvConverter::Naa2TlvConverter()
Toshihiro Shimizu 890ddd
	: MaxColorCount(1000), m_regionRas(0), m_borderRas(0), m_dotRas(0), m_syntheticInkRas(0), m_inkThickness(0), m_palette(0), m_valid(false)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Naa2TlvConverter::~Naa2TlvConverter()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	delete m_regionRas;
Toshihiro Shimizu 890ddd
	delete m_borderRas;
Toshihiro Shimizu 890ddd
	delete m_dotRas;
Toshihiro Shimizu 890ddd
	delete m_syntheticInkRas;
Toshihiro Shimizu 890ddd
	if (m_palette)
Toshihiro Shimizu 890ddd
		m_palette->release();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void Naa2TlvConverter::setPalette(TPalette *palette)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_palette != palette) {
Toshihiro Shimizu 890ddd
		if (palette)
Toshihiro Shimizu 890ddd
			palette->addRef();
Toshihiro Shimizu 890ddd
		if (m_palette)
Toshihiro Shimizu 890ddd
			m_palette->release();
Toshihiro Shimizu 890ddd
		m_palette = palette;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void Naa2TlvConverter::process(const TRaster32P &srcRas)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_valid = false;
Toshihiro Shimizu 890ddd
	setSourceImage(srcRas);
Toshihiro Shimizu 890ddd
	if (!m_valid)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	separateRegions();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	computeLinks();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	findRegionBorders();
Toshihiro Shimizu 890ddd
	erodeRegions();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	findLargePaints();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	findBackgroundRegions();
Toshihiro Shimizu 890ddd
	findMainInks();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// computeMainInkThickness();
Toshihiro Shimizu 890ddd
	findThinInks();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	measureThickness();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//findPaints();
Toshihiro Shimizu 890ddd
	findPaints2();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	findThinPaints();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	findSuspectInks();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	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
Toshihiro Shimizu 890ddd
void Naa2TlvConverter::setSourceImage(const TRaster32P &srcRas)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int lx = srcRas->getSize().lx;
Toshihiro Shimizu 890ddd
	int ly = srcRas->getSize().ly;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_colors.clear();
Toshihiro Shimizu 890ddd
	m_regions.clear();
Toshihiro Shimizu 890ddd
	delete m_regionRas;
Toshihiro Shimizu 890ddd
	m_regionRas = new WorkRaster<unsigned short="">(lx, ly);</unsigned>
Toshihiro Shimizu 890ddd
	delete m_borderRas;
Toshihiro Shimizu 890ddd
	m_borderRas = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	delete m_dotRas;
Toshihiro Shimizu 890ddd
	m_dotRas = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	delete m_syntheticInkRas;
Toshihiro Shimizu 890ddd
	m_syntheticInkRas = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QMap<tpixel32, int=""> colorTable;</tpixel32,>
Toshihiro Shimizu 890ddd
	for (int y = 0; y < ly; y++) {
Toshihiro Shimizu 890ddd
		TPixel32 *srcScanLine = srcRas->pixels(y);
Toshihiro Shimizu 890ddd
		unsigned short *regionScanLine = m_regionRas->pixels(y);
Toshihiro Shimizu 890ddd
		for (int x = 0; x < lx; x++) {
Toshihiro Shimizu 890ddd
			TPixel32 srcPix = overPixOnWhite(srcScanLine[x]);
Toshihiro Shimizu 890ddd
			QMap<tpixel32, int="">::ConstIterator it = colorTable.find(srcPix);</tpixel32,>
Toshihiro Shimizu 890ddd
			if (it == colorTable.end()) {
Toshihiro Shimizu 890ddd
				// found new color (and therefore new region)
Toshihiro Shimizu 890ddd
				RegionInfo r;
Toshihiro Shimizu 890ddd
				// add new color
Toshihiro Shimizu 890ddd
				r.colorIndex = m_colors.count();
Toshihiro Shimizu 890ddd
				m_colors.append(srcPix);
Toshihiro Shimizu 890ddd
				r.pixelCount = 1;
Toshihiro Shimizu 890ddd
				// add new region
Toshihiro Shimizu 890ddd
				int regionIndex = m_regions.count();
Toshihiro Shimizu 890ddd
				m_regions.append(r);
Toshihiro Shimizu 890ddd
				// update raster and colorTable
Toshihiro Shimizu 890ddd
				regionScanLine[x] = regionIndex;
Toshihiro Shimizu 890ddd
				colorTable.insert(srcPix, regionIndex);
Toshihiro Shimizu 890ddd
				if (m_colors.count() > MaxColorCount) {
Toshihiro Shimizu 890ddd
					return;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			} else {
Toshihiro Shimizu 890ddd
				// already defined color
Toshihiro Shimizu 890ddd
				int regionIndex = it.value();
Toshihiro Shimizu 890ddd
				regionScanLine[x] = regionIndex;
Toshihiro Shimizu 890ddd
				m_regions[regionIndex].pixelCount++;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	m_valid = true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// color-based regions => connection-based regions  (i.e. split unconnected region parts)
Toshihiro Shimizu 890ddd
// note: rebuild m_regions
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void Naa2TlvConverter::separateRegions()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!m_regionRas)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	const int lx = m_regionRas->getLx();
Toshihiro Shimizu 890ddd
	const int ly = m_regionRas->getLy();
Toshihiro Shimizu 890ddd
	const int wrap = lx;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// we assume that m_regions contains almost no information (except: m_regions[i].colorIndex == i)
Toshihiro Shimizu 890ddd
	m_regions.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	WorkRaster<int> wb(lx, ly); // work buffer</int>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QVector<int> regionMap; // wb pixels => region indices</int>
Toshihiro Shimizu 890ddd
	QList<int> freeRegions;</int>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int y = 0; y < ly; y++) {
Toshihiro Shimizu 890ddd
		unsigned short *waScanLine = m_regionRas->pixels(y);
Toshihiro Shimizu 890ddd
		int *wbScanLine = wb.pixels(y);
Toshihiro Shimizu 890ddd
		for (int x = 0; x < lx; x++) {
Toshihiro Shimizu 890ddd
			int c = waScanLine[x];
Toshihiro Shimizu 890ddd
			int cUp = y > 0 ? waScanLine[x - wrap] : -1;
Toshihiro Shimizu 890ddd
			int cLeft = x > 0 ? waScanLine[x - 1] : -1;
Toshihiro Shimizu 890ddd
			int cUpLeft = x > 0 && y > 0 ? waScanLine[x - wrap - 1] : -1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (c != cUp && c != cLeft && c != cUpLeft) {
Toshihiro Shimizu 890ddd
				// no connection: create a new region
Toshihiro Shimizu 890ddd
				Q_ASSERT(0 <= c && c < m_colors.count());
Toshihiro Shimizu 890ddd
				RegionInfo region;
Toshihiro Shimizu 890ddd
				region.colorIndex = c;
Toshihiro Shimizu 890ddd
				int regionIndex;
Toshihiro Shimizu 890ddd
				if (!freeRegions.empty()) {
Toshihiro Shimizu 890ddd
					// use a previously discarded region
Toshihiro Shimizu 890ddd
					regionIndex = freeRegions.back();
Toshihiro Shimizu 890ddd
					freeRegions.pop_back();
Toshihiro Shimizu 890ddd
					m_regions[regionIndex] = region;
Toshihiro Shimizu 890ddd
				} else {
Toshihiro Shimizu 890ddd
					// create a new region
Toshihiro Shimizu 890ddd
					regionIndex = m_regions.count();
Toshihiro Shimizu 890ddd
					m_regions.append(region);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
				wbScanLine[x] = regionMap.count();
Toshihiro Shimizu 890ddd
				regionMap.append(regionIndex);
Toshihiro Shimizu 890ddd
			} else {
Toshihiro Shimizu 890ddd
				// at least one connection
Toshihiro Shimizu 890ddd
				if (c == cUpLeft)
Toshihiro Shimizu 890ddd
					wbScanLine[x] = wbScanLine[x - wrap - 1];
Toshihiro Shimizu 890ddd
				else if (c == cUp)
Toshihiro Shimizu 890ddd
					wbScanLine[x] = wbScanLine[x - wrap];
Toshihiro Shimizu 890ddd
				else {
Toshihiro Shimizu 890ddd
					Q_ASSERT(c == cLeft);
Toshihiro Shimizu 890ddd
					wbScanLine[x] = wbScanLine[x - 1];
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// merge if needed
Toshihiro Shimizu 890ddd
			if (cUp == cLeft && cUp >= 0 && regionMap[wbScanLine[x - 1]] != regionMap[wbScanLine[x - wrap]]) {
Toshihiro Shimizu 890ddd
				// merge
Toshihiro Shimizu 890ddd
				int pixelToDiscard = wbScanLine[x - 1];
Toshihiro Shimizu 890ddd
				int pixelToKeep = wbScanLine[x - wrap];
Toshihiro Shimizu 890ddd
				Q_ASSERT(pixelToDiscard != pixelToKeep);
Toshihiro Shimizu 890ddd
				int regionToDiscard = regionMap[pixelToDiscard];
Toshihiro Shimizu 890ddd
				int regionToKeep = regionMap[pixelToKeep];
Toshihiro Shimizu 890ddd
				Q_ASSERT(regionToDiscard != regionToKeep);
Toshihiro Shimizu 890ddd
				Q_ASSERT(m_regions[regionToDiscard].type != RegionInfo::Unused);
Toshihiro Shimizu 890ddd
				Q_ASSERT(m_regions[regionToKeep].type != RegionInfo::Unused);
Toshihiro Shimizu 890ddd
				for (int i = 0; i < regionMap.count(); i++)
Toshihiro Shimizu 890ddd
					if (regionMap[i] == regionToDiscard)
Toshihiro Shimizu 890ddd
						regionMap[i] = regionToKeep;
Toshihiro Shimizu 890ddd
				//wbScanLine[x] = pixelToKeep;
Toshihiro Shimizu 890ddd
				m_regions[regionToDiscard].type = RegionInfo::Unused;
Toshihiro Shimizu 890ddd
				freeRegions.append(regionToDiscard);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// fill gaps
Toshihiro Shimizu 890ddd
	for (;;) {
Toshihiro Shimizu 890ddd
		// just remove topmost Unused regions
Toshihiro Shimizu 890ddd
		if (!m_regions.empty() && m_regions.back().type == RegionInfo::Unused) {
Toshihiro Shimizu 890ddd
			m_regions.pop_back();
Toshihiro Shimizu 890ddd
			int k = m_regions.count();
Toshihiro Shimizu 890ddd
			freeRegions.removeAll(k);
Toshihiro Shimizu 890ddd
		} else if (!freeRegions.empty()) {
Toshihiro Shimizu 890ddd
			// last region is used, but there is at least a free region with lower index: move it there
Toshihiro Shimizu 890ddd
			int regionToDiscard = m_regions.count() - 1;
Toshihiro Shimizu 890ddd
			int regionToKeep = freeRegions.back();
Toshihiro Shimizu 890ddd
			freeRegions.pop_back();
Toshihiro Shimizu 890ddd
			Q_ASSERT(m_regions[regionToKeep].type == RegionInfo::Unused);
Toshihiro Shimizu 890ddd
			Q_ASSERT(m_regions[regionToDiscard].type != RegionInfo::Unused);
Toshihiro Shimizu 890ddd
			Q_ASSERT(regionToKeep < regionToDiscard);
Toshihiro Shimizu 890ddd
			m_regions[regionToKeep] = m_regions[regionToDiscard];
Toshihiro Shimizu 890ddd
			// pop the region to discard
Toshihiro Shimizu 890ddd
			m_regions.pop_back();
Toshihiro Shimizu 890ddd
			// update map
Toshihiro Shimizu 890ddd
			for (int i = 0; i < regionMap.count(); i++)
Toshihiro Shimizu 890ddd
				if (regionMap[i] == regionToDiscard)
Toshihiro Shimizu 890ddd
					regionMap[i] = regionToKeep;
Toshihiro Shimizu 890ddd
		} else
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	Q_ASSERT(freeRegions.empty());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int i = 0; i < m_regions.count(); i++)
Toshihiro Shimizu 890ddd
		m_regions[i].pixelCount = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// wb => m_regionRas
Toshihiro Shimizu 890ddd
	for (int y = 0; y < ly; y++) {
Toshihiro Shimizu 890ddd
		unsigned short *regionScanLine = m_regionRas->pixels(y);
Toshihiro Shimizu 890ddd
		int *wbScanLine = wb.pixels(y);
Toshihiro Shimizu 890ddd
		for (int x = 0; x < lx; x++) {
Toshihiro Shimizu 890ddd
			int regionIndex = regionMap[wbScanLine[x]];
Toshihiro Shimizu 890ddd
			regionScanLine[x] = (unsigned short)regionIndex;
Toshihiro Shimizu 890ddd
			m_regions[regionIndex].pixelCount++;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
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
Toshihiro Shimizu 890ddd
void Naa2TlvConverter::computeLinks()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!m_regionRas || m_regions.empty())
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	const int lx = m_regionRas->getLx();
Toshihiro Shimizu 890ddd
	const int ly = m_regionRas->getLy();
Toshihiro Shimizu 890ddd
	const int wrap = lx;
Toshihiro Shimizu 890ddd
	unsigned short *waScanLine;
Toshihiro Shimizu 890ddd
	int x;
Toshihiro Shimizu 890ddd
	for (int i = 0; i < m_regions.count(); i++)
Toshihiro Shimizu 890ddd
		m_regions[i].perimeter = 0;
Toshihiro Shimizu 890ddd
	for (int y = 0; y < ly; y++) {
Toshihiro Shimizu 890ddd
		waScanLine = m_regionRas->pixels(y);
Toshihiro Shimizu 890ddd
		for (x = 0; x < lx; x++) {
Toshihiro Shimizu 890ddd
			int c = waScanLine[x];
Toshihiro Shimizu 890ddd
			int cUp = y > 0 ? waScanLine[x - wrap] : -1;
Toshihiro Shimizu 890ddd
			int cLeft = x > 0 ? waScanLine[x - 1] : -1;
Toshihiro Shimizu 890ddd
			if (c != cUp) {
Toshihiro Shimizu 890ddd
				m_regions[c].touchRegion(cUp);
Toshihiro Shimizu 890ddd
				m_regions[c].perimeter++;
Toshihiro Shimizu 890ddd
				if (cUp >= 0) {
Toshihiro Shimizu 890ddd
					m_regions[cUp].touchRegion(c);
Toshihiro Shimizu 890ddd
					m_regions[cUp].perimeter++;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			if (c != cLeft) {
Toshihiro Shimizu 890ddd
				m_regions[c].touchRegion(cLeft);
Toshihiro Shimizu 890ddd
				m_regions[c].perimeter++;
Toshihiro Shimizu 890ddd
				if (cLeft >= 0) {
Toshihiro Shimizu 890ddd
					m_regions[cLeft].touchRegion(c);
Toshihiro Shimizu 890ddd
					m_regions[cLeft].perimeter++;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		m_regions[waScanLine[lx - 1]].touchRegion(-1);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	waScanLine = m_regionRas->pixels(ly - 1);
Toshihiro Shimizu 890ddd
	for (x = 0; x < lx; x++) {
Toshihiro Shimizu 890ddd
		m_regions[waScanLine[x]].touchRegion(-1);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// find background regions :
Toshihiro Shimizu 890ddd
// (almost) white, touching image border
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
void Naa2TlvConverter::findBackgroundRegions()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!m_regionRas || m_regions.empty())
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	int lx = m_regionRas->getLx();
Toshihiro Shimizu 890ddd
	int ly = m_regionRas->getLy();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// find the whitest color
Toshihiro Shimizu 890ddd
	int bgColorIndex = -1;
Toshihiro Shimizu 890ddd
	int maxV = 0;
Toshihiro Shimizu 890ddd
	for (int i = 0; i < m_colors.count(); i++) {
Toshihiro Shimizu 890ddd
		TPixel color = m_colors.at(i);
Toshihiro Shimizu 890ddd
		int v = color.r + color.g + color.b;
Toshihiro Shimizu 890ddd
		int a = qMin(color.r, qMin(color.g, color.b));
Toshihiro Shimizu 890ddd
		if (a < 230)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		if (v > maxV) {
Toshihiro Shimizu 890ddd
			bgColorIndex = i;
Toshihiro Shimizu 890ddd
			maxV = v;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (bgColorIndex < 0) {
Toshihiro Shimizu 890ddd
		// no white found. no bg region
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int i = 0; i < m_regions.count(); i++) {
Toshihiro Shimizu 890ddd
		RegionInfo ®ion = m_regions[i];
Toshihiro Shimizu 890ddd
		if (region.colorIndex == bgColorIndex && region.links.contains(-1)) {
Toshihiro Shimizu 890ddd
			region.type = RegionInfo::Background;
Toshihiro Shimizu 890ddd
			;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
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
Toshihiro Shimizu 890ddd
void Naa2TlvConverter::findRegionBorders()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!m_regionRas)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	int lx = m_regionRas->getLx();
Toshihiro Shimizu 890ddd
	int ly = m_regionRas->getLy();
Toshihiro Shimizu 890ddd
	delete m_borderRas;
Toshihiro Shimizu 890ddd
	m_borderRas = new WorkRaster<unsigned char="">(lx, ly);</unsigned>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	static const int dd[][2] = {{-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// find region-region boundaries
Toshihiro Shimizu 890ddd
	for (int y = 0; y < ly; y++) {
Toshihiro Shimizu 890ddd
		unsigned short *workScanLine = m_regionRas->pixels(y);
Toshihiro Shimizu 890ddd
		unsigned char *borderScanLine = m_borderRas->pixels(y);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (int x = 0; x < lx; x++) {
Toshihiro Shimizu 890ddd
			int k = workScanLine[x];
Toshihiro Shimizu 890ddd
			Q_ASSERT(0 <= k && k < m_regions.count());
Toshihiro Shimizu 890ddd
			int isBoundary = 0;
Toshihiro Shimizu 890ddd
			for (int j = 0; j < 8; j++) {
Toshihiro Shimizu 890ddd
				int x1 = x + dd[j][0], y1 = y + dd[j][1];
Toshihiro Shimizu 890ddd
				if (0 <= x1 && x1 < lx && 0 <= y1 && y1 < ly) {
Toshihiro Shimizu 890ddd
					int k1 = m_regionRas->pixels(y1)[x1];
Toshihiro Shimizu 890ddd
					if (k1 != k) {
Toshihiro Shimizu 890ddd
						isBoundary = 1;
Toshihiro Shimizu 890ddd
						break;
Toshihiro Shimizu 890ddd
					}
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			borderScanLine[x] = isBoundary;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
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
Toshihiro Shimizu 890ddd
// update m_regions[i].boundaries (histogram : boundaries[k] is the number of pixels belonging to that region with m_border[pix] == k)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void Naa2TlvConverter::erodeRegions()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	QTime clock;
Toshihiro Shimizu 890ddd
	clock.start();
Toshihiro Shimizu 890ddd
	if (!m_regionRas || !m_borderRas)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	int lx = m_regionRas->getLx();
Toshihiro Shimizu 890ddd
	int ly = m_regionRas->getLy();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	static const int dd[][2] = {{-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int iter = 0; iter < 10; iter++) {
Toshihiro Shimizu 890ddd
		for (int y = 0; y < ly; y++) {
Toshihiro Shimizu 890ddd
			unsigned short *workScanLine = m_regionRas->pixels(y);
Toshihiro Shimizu 890ddd
			unsigned char *borderScanLine = m_borderRas->pixels(y);
Toshihiro Shimizu 890ddd
			for (int x = 0; x < lx; x++) {
Toshihiro Shimizu 890ddd
				if (borderScanLine[x] != iter + 1)
Toshihiro Shimizu 890ddd
					continue;
Toshihiro Shimizu 890ddd
				int c = workScanLine[x];
Toshihiro Shimizu 890ddd
				for (int j = 0; j < 8; j++) {
Toshihiro Shimizu 890ddd
					int x1 = x + dd[j][0], y1 = y + dd[j][1];
Toshihiro Shimizu 890ddd
					if (!(0 <= x1 && x1 < lx && 0 <= y1 && y1 < ly))
Toshihiro Shimizu 890ddd
						continue;
Toshihiro Shimizu 890ddd
					int c1 = m_regionRas->pixels(y1)[x1];
Toshihiro Shimizu 890ddd
					int b1 = m_borderRas->pixels(y1)[x1];
Toshihiro Shimizu 890ddd
					if (c1 == c && b1 == 0)
Toshihiro Shimizu 890ddd
						m_borderRas->pixels(y1)[x1] = iter + 2;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int i = 0; i < m_regions.count(); i++)
Toshihiro Shimizu 890ddd
		m_regions[i].boundaries.clear();
Toshihiro Shimizu 890ddd
	for (int y = 0; y < ly; y++) {
Toshihiro Shimizu 890ddd
		unsigned short *workScanLine = m_regionRas->pixels(y);
Toshihiro Shimizu 890ddd
		unsigned char *borderScanLine = m_borderRas->pixels(y);
Toshihiro Shimizu 890ddd
		for (int x = 0; x < lx; x++) {
Toshihiro Shimizu 890ddd
			int c = workScanLine[x];
Toshihiro Shimizu 890ddd
			int b = borderScanLine[x];
Toshihiro Shimizu 890ddd
			RegionInfo &r = m_regions[c];
Toshihiro Shimizu 890ddd
			QList<int> &bs = r.boundaries;</int>
Toshihiro Shimizu 890ddd
			while (bs.count() <= b)
Toshihiro Shimizu 890ddd
				bs.append(0);
Toshihiro Shimizu 890ddd
			bs[b]++;
Toshihiro Shimizu 890ddd
			if (b == bs.count() - 1)
Toshihiro Shimizu 890ddd
				r.pos = QPoint(x, y);
Toshihiro Shimizu 890ddd
			if (r.x0 > r.x1) {
Toshihiro Shimizu 890ddd
				r.x0 = r.x1 = x;
Toshihiro Shimizu 890ddd
				r.y0 = r.y1 = y;
Toshihiro Shimizu 890ddd
			} else {
Toshihiro Shimizu 890ddd
				if (x < r.x0)
Toshihiro Shimizu 890ddd
					r.x0 = x;
Toshihiro Shimizu 890ddd
				else if (x > r.x1)
Toshihiro Shimizu 890ddd
					r.x1 = x;
Toshihiro Shimizu 890ddd
				if (y < r.y0)
Toshihiro Shimizu 890ddd
					r.y0 = y;
Toshihiro Shimizu 890ddd
				else if (y > r.y1)
Toshihiro Shimizu 890ddd
					r.y1 = y;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	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
Toshihiro Shimizu 890ddd
void Naa2TlvConverter::findMainInks()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int i = 0; i < m_regions.count(); i++) {
Toshihiro Shimizu 890ddd
		RegionInfo ®ion = m_regions[i];
Toshihiro Shimizu 890ddd
		if (region.type != RegionInfo::Unknown)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		if (region.isBackground() || region.type == RegionInfo::LargePaint || region.boundaries[0] > 0)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		double ap2 = 100000.0 * (double)region.pixelCount / pow((double)region.perimeter, 2);
Toshihiro Shimizu 890ddd
		if (ap2 > 100)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		foreach (int c, region.links.keys()) {
Toshihiro Shimizu 890ddd
			if (c >= 0 && (m_regions[c].isBackground() || m_regions[c].type == RegionInfo::LargePaint)) {
Toshihiro Shimizu 890ddd
				int strength = region.links[c];
Toshihiro Shimizu 890ddd
				if (strength > 50) {
Toshihiro Shimizu 890ddd
					m_regions[i].type = RegionInfo::MainInk;
Toshihiro Shimizu 890ddd
					break;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
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
Toshihiro Shimizu 890ddd
void Naa2TlvConverter::computeMainInkThickness()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_inkThickness = 0.0;
Toshihiro Shimizu 890ddd
	int largestArea = 0;
Toshihiro Shimizu 890ddd
	for (int i = 0; i < m_regions.count(); i++) {
Toshihiro Shimizu 890ddd
		if (m_regions[i].type != RegionInfo::MainInk)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		if (m_regions[i].pixelCount < largestArea)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		largestArea = m_regions[i].pixelCount;
Toshihiro Shimizu 890ddd
		if (i == 55) {
Toshihiro Shimizu 890ddd
			int x = 123;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		QList<int> &bs = m_regions[i].boundaries;</int>
Toshihiro Shimizu 890ddd
		Q_ASSERT(bs[1] > 0);
Toshihiro Shimizu 890ddd
		int perimeter = m_regions[i].perimeter;
Toshihiro Shimizu 890ddd
		int area = bs[1];
Toshihiro Shimizu 890ddd
		for (int j = 2; j < bs.count() && bs[j] * 2 > bs[1]; j++)
Toshihiro Shimizu 890ddd
			area += bs[j];
Toshihiro Shimizu 890ddd
		if (perimeter > 0) {
Toshihiro Shimizu 890ddd
			m_inkThickness = 2 * (double)area / (double)perimeter;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void Naa2TlvConverter::findLargePaints()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!m_regionRas || !m_borderRas || m_regions.empty())
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	QSet<int> largePaintColors;</int>
Toshihiro Shimizu 890ddd
	for (int i = 0; i < m_regions.count(); i++) {
Toshihiro Shimizu 890ddd
		RegionInfo ®ion = m_regions[i];
Toshihiro Shimizu 890ddd
		if (region.type != RegionInfo::Unknown)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		QList<int> &bs = region.boundaries;</int>
Toshihiro Shimizu 890ddd
		if (bs[0] > 0) {
Toshihiro Shimizu 890ddd
			region.type = RegionInfo::LargePaint;
Toshihiro Shimizu 890ddd
			largePaintColors.insert(region.colorIndex);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	for (int i = 0; i < m_regions.count(); i++) {
Toshihiro Shimizu 890ddd
		RegionInfo ®ion = m_regions[i];
Toshihiro Shimizu 890ddd
		if (region.type != RegionInfo::Unknown)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		if (largePaintColors.contains(region.colorIndex))
Toshihiro Shimizu 890ddd
			region.type = RegionInfo::LargePaint;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void Naa2TlvConverter::findThinInks()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!m_regionRas || !m_borderRas || m_regions.empty())
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	for (int i = 0; i < m_regions.count(); i++) {
Toshihiro Shimizu 890ddd
		RegionInfo ®ion = m_regions[i];
Toshihiro Shimizu 890ddd
		if (region.type != RegionInfo::Unknown)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		QList<int> &bs = region.boundaries;</int>
Toshihiro Shimizu 890ddd
		if (bs.count() == 2)
Toshihiro Shimizu 890ddd
			region.type = RegionInfo::ThinInk;
Toshihiro Shimizu 890ddd
		else if (bs.count() == 3) {
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
			if (bs[2] * 5 < bs[1])
Toshihiro Shimizu 890ddd
				region.type = RegionInfo::ThinInk;
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
			int k = 1;
Toshihiro Shimizu 890ddd
			int s = 0;
Toshihiro Shimizu 890ddd
			while (k < bs.count() && s * 100 < region.pixelCount * 90)
Toshihiro Shimizu 890ddd
				s += bs[k++];
Toshihiro Shimizu 890ddd
			if (region.pixelCount > 100 && k <= 3)
Toshihiro Shimizu 890ddd
				region.type = RegionInfo::ThinInk; // era Ink per qualche ragione
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void Naa2TlvConverter::findPaints()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	for (int i = 0; i < m_regions.count(); i++) {
Toshihiro Shimizu 890ddd
		RegionInfo ®ion = m_regions[i];
Toshihiro Shimizu 890ddd
		if (region.type != RegionInfo::Unknown)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		foreach (int c, m_regions[i].links.keys()) {
Toshihiro Shimizu 890ddd
			if (c >= 0 && m_regions[c].isInk()) {
Toshihiro Shimizu 890ddd
				m_regions[i].type = RegionInfo::Paint;
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void Naa2TlvConverter::findPaints2()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	double avThickness = 0.0;
Toshihiro Shimizu 890ddd
	int m = 0;
Toshihiro Shimizu 890ddd
	for (int i = 0; i < m_regions.count(); i++) {
Toshihiro Shimizu 890ddd
		RegionInfo ®ion = m_regions[i];
Toshihiro Shimizu 890ddd
		if (region.type == RegionInfo::MainInk) {
Toshihiro Shimizu 890ddd
			avThickness += region.thickness * region.pixelCount;
Toshihiro Shimizu 890ddd
			m += region.pixelCount;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (m > 0) {
Toshihiro Shimizu 890ddd
		avThickness = avThickness / m;
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		avThickness = 1.5; // this should never happen
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int i = 0; i < m_regions.count(); i++) {
Toshihiro Shimizu 890ddd
		RegionInfo ®ion = m_regions[i];
Toshihiro Shimizu 890ddd
		if (region.type != RegionInfo::Unknown)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (region.thickness > 0.0) {
Toshihiro Shimizu 890ddd
			if (region.thickness < 1.2 * avThickness)
Toshihiro Shimizu 890ddd
				region.type = RegionInfo::Ink;
Toshihiro Shimizu 890ddd
			else
Toshihiro Shimizu 890ddd
				region.type = RegionInfo::Paint;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void Naa2TlvConverter::findThinPaints()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int lx = m_regionRas->getLx();
Toshihiro Shimizu 890ddd
	int ly = m_regionRas->getLy();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QList<int> regions;</int>
Toshihiro Shimizu 890ddd
	for (int i = 0; i < m_regions.count(); i++) {
Toshihiro Shimizu 890ddd
		RegionInfo ®ion = m_regions[i];
Toshihiro Shimizu 890ddd
		if (!region.isInk())
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		if (region.type == RegionInfo::MainInk)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int inkBoundary = 0;
Toshihiro Shimizu 890ddd
		QMap<int, int="">::ConstIterator it;</int,>
Toshihiro Shimizu 890ddd
		for (it = region.links.begin(); it != region.links.end(); ++it) {
Toshihiro Shimizu 890ddd
			int c = it.key();
Toshihiro Shimizu 890ddd
			int linkStrength = it.value(); // number of contact points
Toshihiro Shimizu 890ddd
			if (c >= 0 && m_regions[c].isInk())
Toshihiro Shimizu 890ddd
				inkBoundary += linkStrength;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		region.inkBoundary = inkBoundary;
Toshihiro Shimizu 890ddd
		if (inkBoundary * 100 > region.perimeter * 80)
Toshihiro Shimizu 890ddd
			regions.append(i);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	foreach (int c, regions)
Toshihiro Shimizu 890ddd
		m_regions[c].type = RegionInfo::SmallPaint;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void Naa2TlvConverter::findSuspectInks()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	QMultiMap<tuint32, int=""> paintColorTable;</tuint32,>
Toshihiro Shimizu 890ddd
	for (int i = 0; i < m_regions.count(); i++) {
Toshihiro Shimizu 890ddd
		RegionInfo ®ion = m_regions[i];
Toshihiro Shimizu 890ddd
		if (0 == (region.type & RegionInfo::Paint))
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		TPixel32 color = m_colors[region.colorIndex];
Toshihiro Shimizu 890ddd
		if (color == TPixel32(0, 0, 0)) {
Toshihiro Shimizu 890ddd
			int x = 1234;
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		TUINT32 rawColor = *(TUINT32 *)&color;
Toshihiro Shimizu 890ddd
		paintColorTable.insert(rawColor, i);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int count = 0;
Toshihiro Shimizu 890ddd
	for (int i = 0; i < m_regions.count(); i++) {
Toshihiro Shimizu 890ddd
		RegionInfo ®ion = m_regions[i];
Toshihiro Shimizu 890ddd
		if (region.isInk() && region.links.size() == 2) {
Toshihiro Shimizu 890ddd
			int ra = region.links.keys().at(0), rb = region.links.keys().at(1);
Toshihiro Shimizu 890ddd
			if (ra >= 0 && rb >= 0) {
Toshihiro Shimizu 890ddd
				if (!m_regions[ra].isInk())
Toshihiro Shimizu 890ddd
					qSwap(ra, rb);
Toshihiro Shimizu 890ddd
				if (m_regions[ra].isInk() && !m_regions[rb].isInk()) {
Toshihiro Shimizu 890ddd
					int sa = region.links[ra];
Toshihiro Shimizu 890ddd
					int sb = region.links[rb];
Toshihiro Shimizu 890ddd
					if (sa > sb) {
Toshihiro Shimizu 890ddd
						region.type = RegionInfo::Paint;
Toshihiro Shimizu 890ddd
						count++;
Toshihiro Shimizu 890ddd
						continue;
Toshihiro Shimizu 890ddd
					}
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (region.type != RegionInfo::ThinInk)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		TUINT32 rawColor = *(TUINT32 *)&m_colors[region.colorIndex];
Toshihiro Shimizu 890ddd
		if (paintColorTable.contains(rawColor)) {
Toshihiro Shimizu 890ddd
			region.type = RegionInfo::Unknown;
Toshihiro Shimizu 890ddd
			count++;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int i = 0; i < m_regions.count(); i++) {
Toshihiro Shimizu 890ddd
		RegionInfo ®ion = m_regions[i];
Toshihiro Shimizu 890ddd
		if (region.isInk() && 10 <= region.pixelCount && region.pixelCount < 100) {
Toshihiro Shimizu 890ddd
			int lx = region.x1 - region.x0 + 1;
Toshihiro Shimizu 890ddd
			int ly = region.y1 - region.y0 + 1;
Toshihiro Shimizu 890ddd
			int d = qMax(lx, ly);
Toshihiro Shimizu 890ddd
			if (qMin(lx, ly) * 2 > qMax(lx, ly) && region.pixelCount > d * d / 2) {
Toshihiro Shimizu 890ddd
				region.type = RegionInfo::Paint;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (region.type == RegionInfo::Paint || region.type == RegionInfo::Unknown) {
Toshihiro Shimizu 890ddd
			bool isInk = false;
Toshihiro Shimizu 890ddd
			if (region.boundaries.at(0) == 0) {
Toshihiro Shimizu 890ddd
				if (region.boundaries.count() == 2)
Toshihiro Shimizu 890ddd
					isInk = true;
Toshihiro Shimizu 890ddd
				else if (region.boundaries.count() == 3) {
Toshihiro Shimizu 890ddd
					int b1 = region.boundaries.at(1);
Toshihiro Shimizu 890ddd
					int b2 = region.boundaries.at(2);
Toshihiro Shimizu 890ddd
					if (b1 * 2 < b2)
Toshihiro Shimizu 890ddd
						isInk = true;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			if (isInk)
Toshihiro Shimizu 890ddd
				region.type = RegionInfo::Ink;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void Naa2TlvConverter::assignColorTypes()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!m_regionRas || !m_borderRas || m_regions.empty())
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	int lx = m_regionRas->getLx();
Toshihiro Shimizu 890ddd
	int ly = m_regionRas->getLy();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int i = 0; i < m_regions.count(); i++) {
Toshihiro Shimizu 890ddd
		RegionInfo ®ion = m_regions[i];
Toshihiro Shimizu 890ddd
		if (region.type != RegionInfo::Unknown)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		QList<int> &bs = region.boundaries;</int>
Toshihiro Shimizu 890ddd
		if (bs[0] > 0) {
Toshihiro Shimizu 890ddd
			region.type = RegionInfo::LargePaint;
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			int b = 0;
Toshihiro Shimizu 890ddd
			for (int j = 1; j <= 2 && j < bs.count(); j++)
Toshihiro Shimizu 890ddd
				b += bs[j];
Toshihiro Shimizu 890ddd
			if (region.pixelCount > 200 && (region.pixelCount - b) * 10 < region.pixelCount) {
Toshihiro Shimizu 890ddd
				region.type = RegionInfo::ThinInk;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void Naa2TlvConverter::addBorderInks() // add syntethic inks: lines between two adjacent fill-regions
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int lx = m_regionRas->getLx();
Toshihiro Shimizu 890ddd
	int ly = m_regionRas->getLy();
Toshihiro Shimizu 890ddd
	static const int dd[][2] = {{0, -1}, {-1, 0}, {1, 0}, {0, 1}, {1, 1}, {-1, -1}, {-1, 1}, {1, -1}};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_syntheticInkRas = new WorkRaster<unsigned char="">(lx, ly);</unsigned>
Toshihiro Shimizu 890ddd
	for (int i = 0; i < lx * ly; i++)
Toshihiro Shimizu 890ddd
		m_syntheticInkRas->pixels(0)[i] = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int borderInkColorIndex = m_colors.count();
Toshihiro Shimizu 890ddd
	m_colors.append(TPixel32(255, 0, 0));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	RegionInfo borderInkRegion;
Toshihiro Shimizu 890ddd
	borderInkRegion.type = RegionInfo::SyntheticInk;
Toshihiro Shimizu 890ddd
	borderInkRegion.colorIndex = borderInkColorIndex;
Toshihiro Shimizu 890ddd
	int borderInkRegionIndex = m_regions.count();
Toshihiro Shimizu 890ddd
	m_regions.append(borderInkRegion);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int y = 0; y < ly; y++) {
Toshihiro Shimizu 890ddd
		unsigned short *workScanLine = m_regionRas->pixels(y);
Toshihiro Shimizu 890ddd
		unsigned char *borderScanLine = m_borderRas->pixels(y);
Toshihiro Shimizu 890ddd
		for (int x = 0; x < lx; x++) {
Toshihiro Shimizu 890ddd
			int c = workScanLine[x];
Toshihiro Shimizu 890ddd
			if (borderScanLine[x] != 1)
Toshihiro Shimizu 890ddd
				continue; // consider border pixel only
Toshihiro Shimizu 890ddd
			if (0 == (m_regions[c].type & RegionInfo::Paint) && m_regions[c].type != RegionInfo::Unknown)
Toshihiro Shimizu 890ddd
				continue; // consider paint pixels only
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// is touching a different no-ink pixel?
Toshihiro Shimizu 890ddd
			bool touchesOtherRegion = false;
Toshihiro Shimizu 890ddd
			for (int j = 0; j < 8; j++) {
Toshihiro Shimizu 890ddd
				int x1 = x + dd[j][0], y1 = y + dd[j][1];
Toshihiro Shimizu 890ddd
				if (0 <= x1 && x1 < lx && 0 <= y1 && y1 < ly) {
Toshihiro Shimizu 890ddd
					int c1 = m_regionRas->pixels(y1)[x1];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					if (m_regions[c1].type == RegionInfo::Background) {
Toshihiro Shimizu 890ddd
						touchesOtherRegion = true;
Toshihiro Shimizu 890ddd
						break;
Toshihiro Shimizu 890ddd
					} else if (m_regions[c1].type == RegionInfo::Unknown || (m_regions[c1].type & RegionInfo::Paint) != 0) {
Toshihiro Shimizu 890ddd
						// OLD: note: we consider only regions with a lower index, to avoid to create double border strokes
Toshihiro Shimizu 890ddd
						// NEW: we put syntetic ink pixels in larger regions
Toshihiro Shimizu 890ddd
						if (m_regions[c1].pixelCount < m_regions[c].pixelCount) {
Toshihiro Shimizu 890ddd
							touchesOtherRegion = true;
Toshihiro Shimizu 890ddd
							break;
Toshihiro Shimizu 890ddd
						}
Toshihiro Shimizu 890ddd
					}
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (touchesOtherRegion) {
Toshihiro Shimizu 890ddd
				m_syntheticInkRas->pixels(y)[x] = 1;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void Naa2TlvConverter::measureThickness()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	QTime timer;
Toshihiro Shimizu 890ddd
	timer.start();
Toshihiro Shimizu 890ddd
	if (!m_regionRas || !m_borderRas)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	unsigned short *regionBuffer = m_regionRas->pixels();
Toshihiro Shimizu 890ddd
	unsigned char *borderBuffer = m_borderRas->pixels();
Toshihiro Shimizu 890ddd
	int lx = m_regionRas->getLx();
Toshihiro Shimizu 890ddd
	int ly = m_regionRas->getLy();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!m_dotRas || m_dotRas->getLx() != lx || m_dotRas->getLy() != ly) {
Toshihiro Shimizu 890ddd
		delete m_dotRas;
Toshihiro Shimizu 890ddd
		m_dotRas = new WorkRaster<unsigned char="">(lx, ly);</unsigned>
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	memset(m_dotRas->pixels(), 0, lx * ly);
Toshihiro Shimizu 890ddd
	// for(int i=0;i<lx*ly;i++) m_dotras-="">pixels()[i]=0;</lx*ly;i++)>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	unsigned char *dotBuffer = m_dotRas->pixels();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int y = 0; y < ly; y++) {
Toshihiro Shimizu 890ddd
		for (int x = 0; x < lx; x++) {
Toshihiro Shimizu 890ddd
			if (borderBuffer[y * lx + x] != 1)
Toshihiro Shimizu 890ddd
				continue;
Toshihiro Shimizu 890ddd
			if (dotBuffer[y * lx + x] != 0)
Toshihiro Shimizu 890ddd
				continue;
Toshihiro Shimizu 890ddd
			int regionId = regionBuffer[y * lx + x];
Toshihiro Shimizu 890ddd
			RegionInfo ®ion = m_regions[regionId];
Toshihiro Shimizu 890ddd
			int type = region.type;
Toshihiro Shimizu 890ddd
			if (type == RegionInfo::Background || type == RegionInfo::LargePaint || type == RegionInfo::ThinInk)
Toshihiro Shimizu 890ddd
				continue;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			int thickness = measureThickness(x, y);
Toshihiro Shimizu 890ddd
			if (thickness < 1)
Toshihiro Shimizu 890ddd
				continue;
Toshihiro Shimizu 890ddd
			QMap<int, int="">::Iterator it = region.thicknessHistogram.find(thickness);</int,>
Toshihiro Shimizu 890ddd
			if (it != region.thicknessHistogram.end())
Toshihiro Shimizu 890ddd
				it.value() += 1;
Toshihiro Shimizu 890ddd
			else
Toshihiro Shimizu 890ddd
				region.thicknessHistogram.insert(thickness, 1);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int i = 0; i < m_regions.count(); i++) {
Toshihiro Shimizu 890ddd
		RegionInfo ®ion = m_regions[i];
Toshihiro Shimizu 890ddd
		int type = region.type;
Toshihiro Shimizu 890ddd
		if (type == RegionInfo::Background || type == RegionInfo::LargePaint || type == RegionInfo::ThinInk)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		int thicknessCount = 0;
Toshihiro Shimizu 890ddd
		double thickness = 0.0;
Toshihiro Shimizu 890ddd
		for (QMap<int, int="">::Iterator it = region.thicknessHistogram.begin(); it != region.thicknessHistogram.end(); ++it) {</int,>
Toshihiro Shimizu 890ddd
			thicknessCount += it.value();
Toshihiro Shimizu 890ddd
			thickness += it.key() * it.value();
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		if (thicknessCount > 0) {
Toshihiro Shimizu 890ddd
			thickness *= 1.0 / thicknessCount;
Toshihiro Shimizu 890ddd
			region.thickness = thickness;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	qDebug() << "measure thickness. time=" << timer.elapsed();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int Naa2TlvConverter::measureThickness(int x0, int y0)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!m_regionRas || !m_borderRas || !m_dotRas)
Toshihiro Shimizu 890ddd
		return -1;
Toshihiro Shimizu 890ddd
	unsigned short *regionBuffer = m_regionRas->pixels();
Toshihiro Shimizu 890ddd
	unsigned char *borderBuffer = m_borderRas->pixels();
Toshihiro Shimizu 890ddd
	unsigned char *dotBuffer = m_dotRas->pixels();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int lx = m_regionRas->getLx();
Toshihiro Shimizu 890ddd
	int ly = m_regionRas->getLy();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int k0 = lx * y0 + x0;
Toshihiro Shimizu 890ddd
	// no needs to worry about image limits
Toshihiro Shimizu 890ddd
	if (x0 - 1 < 0 || x0 + 1 >= lx || y0 - 1 < 0 || y0 + 1 >= ly)
Toshihiro Shimizu 890ddd
		return -1;
Toshihiro Shimizu 890ddd
	// we must start from a border
Toshihiro Shimizu 890ddd
	if (borderBuffer[k0] != 1)
Toshihiro Shimizu 890ddd
		return -1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// far from other measures
Toshihiro Shimizu 890ddd
	if (dotBuffer[k0] != 0)
Toshihiro Shimizu 890ddd
		return -1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int regionId = regionBuffer[k0];
Toshihiro Shimizu 890ddd
	RegionInfo &info = m_regions[regionId];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// directions
Toshihiro Shimizu 890ddd
	const int dd[8] = {1, lx + 1, lx, lx - 1, -1, -1 - lx, -lx, 1 - lx};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// a is a direction index; a : inside; a+1 : outside
Toshihiro Shimizu 890ddd
	int a = 0;
Toshihiro Shimizu 890ddd
	while (a < 8 && !(regionBuffer[k0 + dd[a]] == regionId && regionBuffer[k0 + dd[(a + 1) % 8]] != regionId))
Toshihiro Shimizu 890ddd
		a++;
Toshihiro Shimizu 890ddd
	if (a == 8) {
Toshihiro Shimizu 890ddd
		// k0 is an isolated point or (strange!) an intern point
Toshihiro Shimizu 890ddd
		qDebug() << "Isolated point or intern point";
Toshihiro Shimizu 890ddd
		return -1;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	int ka = k0 + dd[a];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int b = (a + 2) % 8;
Toshihiro Shimizu 890ddd
	while (regionBuffer[k0 + dd[b]] != regionId)
Toshihiro Shimizu 890ddd
		b = (b + 1) % 8;
Toshihiro Shimizu 890ddd
	// a..b = boundaries
Toshihiro Shimizu 890ddd
	int kb = k0 + dd[b];
Toshihiro Shimizu 890ddd
	if (a == b || ((b + 1) % 8) == a)
Toshihiro Shimizu 890ddd
		return -1; // k0 is a corner
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	dotBuffer[k0] = 1;
Toshihiro Shimizu 890ddd
	dotBuffer[ka] = 2;
Toshihiro Shimizu 890ddd
	dotBuffer[kb] = 3;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int c = (b + 1) % 8;
Toshihiro Shimizu 890ddd
	bool isThin = false;
Toshihiro Shimizu 890ddd
	while (c != a) {
Toshihiro Shimizu 890ddd
		if (regionBuffer[k0 + dd[c]] != regionId) {
Toshihiro Shimizu 890ddd
			isThin = true;
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		c = (c + 1) % 8;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (isThin) {
Toshihiro Shimizu 890ddd
		// stroke larga un pixel, con paint da una parte e dall'altra.
Toshihiro Shimizu 890ddd
		return 1;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int baseLength = 3;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int d = b;
Toshihiro Shimizu 890ddd
	int oldk = k0;
Toshihiro Shimizu 890ddd
	int k = kb;
Toshihiro Shimizu 890ddd
	int lastd2 = 0;
Toshihiro Shimizu 890ddd
	for (int i = 0; i < baseLength; i++) {
Toshihiro Shimizu 890ddd
		int x = k % lx;
Toshihiro Shimizu 890ddd
		int y = k / lx;
Toshihiro Shimizu 890ddd
		if (x <= 1 || x >= lx - 1 || y <= 1 || y >= ly - 1)
Toshihiro Shimizu 890ddd
			break; // just to be sure
Toshihiro Shimizu 890ddd
		int d2 = (x - x0) * (x - x0) + (y - y0) * (y - y0);
Toshihiro Shimizu 890ddd
		if (d2 <= lastd2)
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
		lastd2 = d2;
Toshihiro Shimizu 890ddd
		int d1 = (d + 4) % 8;
Toshihiro Shimizu 890ddd
		d1 = (d1 + 1) % 8;
Toshihiro Shimizu 890ddd
		while (regionBuffer[k + dd[d1]] != regionId)
Toshihiro Shimizu 890ddd
			d1 = (d1 + 1) % 8;
Toshihiro Shimizu 890ddd
		Q_ASSERT(regionBuffer[k + dd[d1]] == regionId);
Toshihiro Shimizu 890ddd
		oldk = k;
Toshihiro Shimizu 890ddd
		k = k + dd[d1];
Toshihiro Shimizu 890ddd
		d = d1;
Toshihiro Shimizu 890ddd
		dotBuffer[k] = 4;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// punto ad un estremo (lungo il confine)
Toshihiro Shimizu 890ddd
	int x1 = k % lx;
Toshihiro Shimizu 890ddd
	int y1 = k / lx;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	d = a;
Toshihiro Shimizu 890ddd
	oldk = k0;
Toshihiro Shimizu 890ddd
	k = ka;
Toshihiro Shimizu 890ddd
	lastd2 = 0;
Toshihiro Shimizu 890ddd
	for (int i = 0; i < baseLength; i++) {
Toshihiro Shimizu 890ddd
		int x = k % lx;
Toshihiro Shimizu 890ddd
		int y = k / lx;
Toshihiro Shimizu 890ddd
		if (x <= 1 || x >= lx - 1 || y <= 1 || y >= ly - 1)
Toshihiro Shimizu 890ddd
			break; // just to be sure
Toshihiro Shimizu 890ddd
		int d2 = (x - x0) * (x - x0) + (y - y0) * (y - y0);
Toshihiro Shimizu 890ddd
		if (d2 <= lastd2)
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
		lastd2 = d2;
Toshihiro Shimizu 890ddd
		int d1 = (d + 4) % 8;
Toshihiro Shimizu 890ddd
		d1 = (d1 + 7) % 8;
Toshihiro Shimizu 890ddd
		while (regionBuffer[k + dd[d1]] != regionId)
Toshihiro Shimizu 890ddd
			d1 = (d1 + 7) % 8;
Toshihiro Shimizu 890ddd
		Q_ASSERT(regionBuffer[k + dd[d1]] == regionId);
Toshihiro Shimizu 890ddd
		oldk = k;
Toshihiro Shimizu 890ddd
		k = k + dd[d1];
Toshihiro Shimizu 890ddd
		d = d1;
Toshihiro Shimizu 890ddd
		dotBuffer[k] = 5;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// punto all'estremo opposto (lungo il confine)
Toshihiro Shimizu 890ddd
	int x2 = k % lx;
Toshihiro Shimizu 890ddd
	int y2 = k / lx;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int dx = y2 - y1, dy = x1 - x2;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int delta2 = dx * dx + dy * dy;
Toshihiro Shimizu 890ddd
	if (delta2 < baseLength * baseLength * 3)
Toshihiro Shimizu 890ddd
		return -1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int adx = abs(dx), ady = abs(dy);
Toshihiro Shimizu 890ddd
	int sgx = dx > 0 ? 1 : -1, sgy = dy > 0 ? 1 : -1;
Toshihiro Shimizu 890ddd
	int thickness = 1;
Toshihiro Shimizu 890ddd
	const int maxThickness = 64;
Toshihiro Shimizu 890ddd
	for (; thickness < maxThickness; thickness++) {
Toshihiro Shimizu 890ddd
		int x, y;
Toshihiro Shimizu 890ddd
		if (adx > ady) {
Toshihiro Shimizu 890ddd
			x = x0 + thickness * sgx;
Toshihiro Shimizu 890ddd
			y = y0 + sgy * (thickness * ady + adx / 2) / adx;
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			y = y0 + thickness * sgy;
Toshihiro Shimizu 890ddd
			x = x0 + sgx * (thickness * adx + ady / 2) / ady;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		k = y * lx + x;
Toshihiro Shimizu 890ddd
		if (0 <= x && x < lx && 0 <= y && y < ly && regionBuffer[k] == regionId)
Toshihiro Shimizu 890ddd
			dotBuffer[k] = 6;
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	return thickness;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TToonzImageP Naa2TlvConverter::makeTlv(bool transparentSyntheticInks)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!m_valid || m_colors.empty() || m_regions.empty() || !m_regionRas)
Toshihiro Shimizu 890ddd
		return TToonzImageP();
Toshihiro Shimizu 890ddd
	int lx = m_regionRas->getLx();
Toshihiro Shimizu 890ddd
	int ly = m_regionRas->getLy();
Toshihiro Shimizu 890ddd
	TPalette *palette = m_palette;
Toshihiro Shimizu 890ddd
	if (!palette)
Toshihiro Shimizu 890ddd
		palette = new TPalette();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TRasterCM32P ras(lx, ly);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QList<int> styleIds;</int>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int i = 0; i < m_colors.count() - 1; i++) {
Toshihiro Shimizu 890ddd
		TPixel32 color = m_colors.at(i);
Toshihiro Shimizu 890ddd
		int styleId = palette->getClosestStyle(color);
Toshihiro Shimizu 890ddd
		TColorStyle *cs = styleId < 0 ? 0 : palette->getStyle(styleId);
Toshihiro Shimizu 890ddd
		if (cs) {
Toshihiro Shimizu 890ddd
			if (cs->getMainColor() != color)
Toshihiro Shimizu 890ddd
				cs = 0;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		if (cs == 0) {
Toshihiro Shimizu 890ddd
			styleId = palette->getPage(0)->addStyle(color);
Toshihiro Shimizu 890ddd
			cs = palette->getStyle(styleId);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		styleIds.append(styleId);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	styleIds.append(0); // syntetic ink
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//int synteticInkStyleId = palette->getPage(0)->addStyle(TPixel32(0,0,0,0));
Toshihiro Shimizu 890ddd
	//styleIds.append(synteticInkStyleId);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int y = 0; y < ly; y++) {
Toshihiro Shimizu 890ddd
		unsigned short *workScanLine = m_regionRas->pixels(y);
Toshihiro Shimizu 890ddd
		TPixelCM32 *outScanLine = ras->pixels(y);
Toshihiro Shimizu 890ddd
		for (int x = 0; x < lx; x++) {
Toshihiro Shimizu 890ddd
			int c = workScanLine[x];
Toshihiro Shimizu 890ddd
			Q_ASSERT(0 <= c && c < m_regions.count());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			int color = m_regions[c].colorIndex;
Toshihiro Shimizu 890ddd
			Q_ASSERT(0 <= color && color < styleIds.count());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			int styleId = styleIds.at(color);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			RegionInfo::Type type = m_regions.at(c).type;
Toshihiro Shimizu 890ddd
			if (type == RegionInfo::Background)
Toshihiro Shimizu 890ddd
				outScanLine[x] = TPixelCM32();
Toshihiro Shimizu 890ddd
			else if (type & RegionInfo::Ink)
Toshihiro Shimizu 890ddd
				outScanLine[x] = TPixelCM32(styleId, 0, 0);
Toshihiro Shimizu 890ddd
			else if (m_syntheticInkRas->pixels(y)[x] == 1)
Toshihiro Shimizu 890ddd
				outScanLine[x] = TPixelCM32(transparentSyntheticInks ? 0 : styleId, styleId, 0);
Toshihiro Shimizu 890ddd
			else
Toshihiro Shimizu 890ddd
				outScanLine[x] = TPixelCM32(0, styleId, 255);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TToonzImageP ti = new TToonzImage(ras, ras->getBounds());
Toshihiro Shimizu 890ddd
	ti->setPalette(palette);
Toshihiro Shimizu 890ddd
	ti->setDpi(72, 72);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return ti;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TVectorImageP Naa2TlvConverter::vectorize(const TToonzImageP &ti)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	CenterlineConfiguration conf;
Toshihiro Shimizu 890ddd
	if (!ti)
Toshihiro Shimizu 890ddd
		return TVectorImageP();
Toshihiro Shimizu 890ddd
	TPalette *palette = ti->getPalette();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	VectorizerCore vc;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TAffine dpiAff;
Toshihiro Shimizu 890ddd
	double factor = Stage::inch;
Toshihiro Shimizu 890ddd
	double dpix = factor / 72, dpiy = factor / 72;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	ti->getDpi(dpix, dpiy);
Toshihiro Shimizu 890ddd
	TPointD center = ti->getRaster()->getCenterD();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (dpix != 0.0 && dpiy != 0.0)
Toshihiro Shimizu 890ddd
		dpiAff = TScale(factor / dpix, factor / dpiy);
Toshihiro Shimizu 890ddd
	factor = norm(dpiAff * TPointD(1, 0));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	conf.m_affine = dpiAff * TTranslation(-center);
Toshihiro Shimizu 890ddd
	conf.m_thickScale = factor;
Toshihiro Shimizu 890ddd
	conf.m_leaveUnpainted = false;
Toshihiro Shimizu 890ddd
	conf.m_makeFrame = true;
Toshihiro Shimizu 890ddd
	conf.m_penalty = 0.0;
Toshihiro Shimizu 890ddd
	conf.m_despeckling = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TImageP img(ti.getPointer());
Toshihiro Shimizu 890ddd
	TVectorImageP vi = vc.vectorize(img, conf, palette);
Toshihiro Shimizu 890ddd
	vi->setPalette(palette);
Toshihiro Shimizu 890ddd
	return vi;
Toshihiro Shimizu 890ddd
}