void Convert2Tlv::removeAntialias(TRasterCM32P &r) { int threshold = (int)(m_antialiasValue * 255.0 / 100.0); int tone; for (int i = 0; i < r->getLy(); i++) { TPixelCM32 *pix = r->pixels(i); for (int j = 0; j < r->getLx(); j++, pix++) if ((tone = pix->getTone()) != 0xff) //tone==ff e tone==0 non vanno toccati mai pix->setTone(tone > threshold ? 0xff : 0); } }
/*--- Toonz Raster LevelのToneを拾う。 ---*/ int StylePicker::pickTone(const TPointD &pos) { if (TToonzImageP ti = m_image) { TRasterCM32P ras = ti->getRaster(); if (!ras) return -1; TPoint point = getRasterPoint(pos); if (!ras->getBounds().contains(point)) return -1; TPixelCM32 col = ras->pixels(point.y)[point.x]; return col.getTone(); } else return -1; }
bool compute(const TPoint &pin, int ink, bool isSelective) { TPixelCM32 *pix; int distance; TPixelCM32 *master; TPoint mp, sp; TPixelCM32 *slave; TPixelCM32 *d11, *d12, *d21, *d22; TPoint d1p1, d1p2, d2p1, d2p2; TPoint p = pin; if (!m_bBox.contains(p)) return false; if ((m_buf + p.y * m_wrap + p.x)->isPurePaint() && ((p = nearestInk(p, 2)) == TPoint(-1, -1))) return false; pix = m_buf + p.y * m_wrap + p.x; /*-- 同じインクの場合はreturn --*/ if (pix->getInk() == ink) return false; if (!ConnectionTable[neighboursCode(pix, p)]) { master = slave = pix; mp = sp = p; distance = 0; } else distance = findTwinPoints(pix, p, master, mp, slave, sp); if (distance == -1) return false; if (!findDam(master, mp, slave, sp, distance, d11, d1p1, d12, d1p2)) d11 = d12 = d21 = d22 = 0; else findDamRev(master, mp, slave, sp, distance, d21, d2p1, d22, d2p2); // vector<pair<TPixelCM32*, int> > oldInks; drawSegment(d1p1, d1p2, damInk, m_saver); drawSegment(d2p1, d2p2, damInk, m_saver); inkSegmentFill(p, ink, isSelective, m_saver); // UINT i; drawSegment(d1p1, d1p2, ink, m_saver); drawSegment(d2p1, d2p2, ink, m_saver); /* for (i=0; i<oldInks.size(); i++) (oldInks[i].first)->setInk(ink);*/ return true; }
void InkSegmenter::drawSegment( const TPoint &p0, const TPoint &p1, int ink, /*vector<pair<TPixelCM32*, int> >& oldInks,*/ TTileSaverCM32 *saver) { int x, y, dx, dy, d, incr_1, incr_2; int x1 = p0.x; int y1 = p0.y; int x2 = p1.x; int y2 = p1.y; if (x1 > x2) { tswap(x1, x2); tswap(y1, y2); } TPixelCM32 *buf = m_r->pixels() + y1 * m_wrap + x1; /*if (buf->getInk()!=damInk) oldInks.push_back(pair<TPixelCM32*, int>(buf, buf->getInk())); if ((m_r->pixels() + y2*m_wrap + x2)->getInk()!=damInk) oldInks.push_back(pair<TPixelCM32*, int>(m_r->pixels() + y2*m_wrap + x2, (m_r->pixels() + y2*m_wrap + x2)->getInk()));*/ if (saver) { saver->save(p0); saver->save(p1); } buf->setInk(ink); (m_r->pixels() + y2 * m_wrap + x2)->setInk(ink); dx = x2 - x1; dy = y2 - y1; x = y = 0; if (dy >= 0) { if (dy <= dx) DRAW_SEGMENT(x, y, dx, dy, (buf++), (buf += m_wrap + 1), SET_INK) else DRAW_SEGMENT(y, x, dy, dx, (buf += m_wrap), (buf += m_wrap + 1), SET_INK) } else {
/*-- (StylePickerTool内で)LineとAreaを切り替えてPickできる。mode: 0=Area, 1=Line, 2=Line&Areas(default) --*/ int StylePicker::pickStyleId(const TPointD &pos, double radius2, int mode) const { int styleId = 0; if (TToonzImageP ti = m_image) { TRasterCM32P ras = ti->getRaster(); TPoint point = getRasterPoint(pos); if (!ras->getBounds().contains(point)) return -1; TPixelCM32 col = ras->pixels(point.y)[point.x]; switch (mode) { case 0: //AREAS styleId = col.getPaint(); break; case 1: //LINES styleId = col.getInk(); break; case 2: //ALL (Line & Area) default: styleId = col.isPurePaint() ? col.getPaint() : col.getInk(); break; } } else if (TRasterImageP ri = m_image) { const TPalette *palette = m_palette.getPointer(); if (!palette) return -1; TRaster32P ras = ri->getRaster(); if (!ras) return -1; TPoint point = getRasterPoint(pos); if (!ras->getBounds().contains(point)) return -1; TPixel32 col = ras->pixels(point.y)[point.x]; styleId = palette->getClosestStyle(col); } else if (TVectorImageP vi = m_image) { // prima cerca lo stile della regione piu' vicina TRegion *r = vi->getRegion(pos); if (r) styleId = r->getStyle(); // poi cerca quello della stroke, ma se prima aveva trovato una regione, richiede che // il click sia proprio sopra la stroke, altrimenti cerca la stroke piu' vicina (max circa 10 pixel) const double maxDist2 = (styleId == 0) ? 100.0 * radius2 : 0; bool strokeFound; double dist2, w, thick; UINT index; //!funzionerebbe ancora meglio con un getNearestStroke che considera //la thickness, cioe' la min distance dalla outline e non dalla centerLine strokeFound = vi->getNearestStroke(pos, w, index, dist2); if (strokeFound) { TStroke *stroke = vi->getStroke(index); thick = stroke->getThickPoint(w).thick; if (dist2 - thick * thick < maxDist2) { assert(stroke); styleId = stroke->getStyle(); } } } return styleId; }
void inkFill(const TRasterCM32P &r, const TPoint &pin, int ink, int searchRay, TTileSaverCM32 *saver, TRect *insideRect) { r->lock(); TPixelCM32 *pixels = (TPixelCM32 *)r->getRawData(); int oldInk; TPoint p = pin; if ((pixels + p.y * r->getWrap() + p.x)->isPurePaint() && (searchRay == 0 || (p = nearestInk(r, p, searchRay)) == TPoint(-1, -1))) { r->unlock(); return; } TPixelCM32 *pix = pixels + (p.y * r->getWrap() + p.x); if (pix->getInk() == ink) { r->unlock(); return; } oldInk = pix->getInk(); std::stack<TPoint> seeds; seeds.push(p); while (!seeds.empty()) { p = seeds.top(); seeds.pop(); if (!r->getBounds().contains(p)) continue; if (insideRect && !insideRect->contains(p)) continue; TPixelCM32 *pix = pixels + (p.y * r->getWrap() + p.x); if (pix->isPurePaint() || pix->getInk() != oldInk) continue; if (saver) saver->save(p); pix->setInk(ink); seeds.push(TPoint(p.x - 1, p.y - 1)); seeds.push(TPoint(p.x - 1, p.y)); seeds.push(TPoint(p.x - 1, p.y + 1)); seeds.push(TPoint(p.x, p.y - 1)); seeds.push(TPoint(p.x, p.y + 1)); seeds.push(TPoint(p.x + 1, p.y - 1)); seeds.push(TPoint(p.x + 1, p.y)); seeds.push(TPoint(p.x + 1, p.y + 1)); } r->unlock(); }
//----------------------------------------------------------------------------- // questa funzione viene chiamata dopo il fill rect delle aree, e colora gli // inchiostri di tipo "autoink" // che confinano con le aree appena fillate con il rect. rbefore e' il rect del // raster prima del rectfill. void fillautoInks(TRasterCM32P &rin, TRect &rect, const TRasterCM32P &rbefore, TPalette *plt) { assert(plt); TRasterCM32P r = rin->extract(rect); assert(r->getSize() == rbefore->getSize()); int i, j; for (i = 0; i < r->getLy(); i++) { TPixelCM32 *pix = r->pixels(i); TPixelCM32 *pixb = rbefore->pixels(i); for (j = 0; j < r->getLx(); j++, pix++, pixb++) { int paint = pix->getPaint(); int tone = pix->getTone(); int ink = pix->getInk(); if (paint != pixb->getPaint() && tone > 0 && tone < 255 && ink != paint && plt->getStyle(ink)->getFlags() != 0) inkFill(rin, TPoint(j, i) + rect.getP00(), paint, 0, NULL, &rect); } } }
void AreaFiller::rectFill(const TRect &rect, int color, bool onlyUnfilled, bool fillPaints, bool fillInks) { // Viene trattato il caso fillInks /*- FillInkのみの場合 -*/ if (!fillPaints) { assert(fillInks); assert(m_ras->getBounds().contains(rect)); for (int y = rect.y0; y <= rect.y1; y++) { TPixelCM32 *pix = m_ras->pixels(y) + rect.x0; for (int x = rect.x0; x <= rect.x1; x++, pix++) pix->setInk(color); } return; } TRect r = m_bounds * rect; int dx = r.x1 - r.x0; int dy = (r.y1 - r.y0) * m_wrap; if (dx < 2 || dy < 2) // rect degenere(area contenuta nulla), skippo. return; std::vector<int> frameSeed(2 * (r.getLx() + r.getLy() - 2)); int x, y, count1, count2; /*- ptrをRect範囲のスタート地点に移動 -*/ Pixel *ptr = m_pixels + r.y0 * m_wrap + r.x0; count1 = 0; count2 = r.y1 - r.y0 + 1; // Se il rettangolo non contiene il bordo del raster e se tutti i pixels // contenuti nel rettangolo sono pure paint non deve fare nulla! if (!rect.contains(m_bounds) && areRectPixelsPurePaint(m_pixels, r, m_wrap)) return; // Viene riempito frameSeed con tutti i paint delle varie aree del rettangolo // di contorno. // Viene verificato se i pixels del rettangolo sono tutti pure paint. /*- 輪郭のPaintのIDをframeseed内に格納 -*/ for (y = r.y0; y <= r.y1; y++, ptr += m_wrap, count1++, count2++) { if (r.x0 > 0) frameSeed[count1] = ptr->getPaint(); if (r.x1 < m_ras->getLx() - 1) frameSeed[count2] = (ptr + dx)->getPaint(); } ptr = m_pixels + r.y0 * m_wrap + r.x0 + 1; count1 = count2; count2 = count1 + r.x1 - r.x0 - 1; for (x = r.x0 + 1; x < r.x1; x++, ptr++, count1++, count2++) { if (r.y0 > 0) frameSeed[count1] = ptr->getPaint(); if (r.y1 < m_ras->getLy() - 1) frameSeed[count2] = (ptr + dy)->getPaint(); } assert(count2 == 2 * (r.getLx() + r.getLy() - 2)); // Viene fillato l'interno e il bordo del rettangolo rect con color Pixel *pix = m_pixels + r.y0 * m_wrap + r.x0; if (onlyUnfilled) for (y = r.y0; y <= r.y1; y++, pix += m_wrap - dx - 1) { for (x = r.x0; x <= r.x1; x++, pix++) { if (pix->getPaint() == 0) // BackgroundStyle pix->setPaint(color); if (fillInks) pix->setInk(color); } } else for (y = r.y0; y <= r.y1; y++, pix += m_wrap - dx - 1) { for (x = r.x0; x <= r.x1; x++, pix++) { pix->setPaint(color); if (fillInks) pix->setInk(color); } } // Vengono fillati i pixel del rettangolo con i paint (mantenuti in frameSeed) // che // c'erano prima di fillare l'intero rettangolo, in questo modo si riportano // al colore originale le aree che non sono chiuse e non dovevano essere // fillate. count1 = 0; FillParameters params; // in order to make the paint to protlude behind the line params.m_prevailing = false; if (r.x0 > 0) for (y = r.y0; y <= r.y1; y++) { params.m_p = TPoint(r.x0, y); params.m_styleId = frameSeed[count1++]; fill(m_ras, params); } else count1 += r.y1 - r.y0 + 1; if (r.x1 < m_ras->getLx() - 1) for (y = r.y0; y <= r.y1; y++) { params.m_p = TPoint(r.x1, y); params.m_styleId = frameSeed[count1++]; fill(m_ras, params); } else count1 += r.y1 - r.y0 + 1; if (r.y0 > 0) for (x = r.x0 + 1; x < r.x1; x++) { params.m_p = TPoint(x, r.y0); params.m_styleId = frameSeed[count1++]; fill(m_ras, params); } else count1 += r.x1 - r.x0 - 1; if (r.y1 < m_ras->getLy() - 1) for (x = r.x0 + 1; x < r.x1; x++) { params.m_p = TPoint(x, r.y1); params.m_styleId = frameSeed[count1++]; fill(m_ras, params); } }
void Convert2Tlv::doFill(TRasterCM32P &rout, const TRaster32P &rin) { //prima passata: si filla solo partendo da pixel senza inchiostro, senza antialiasing(tone==255) for (int i = 0; i < rin->getLy(); i++) { TPixel *pixin = rin->pixels(i); TPixelCM32 *pixout = rout->pixels(i); for (int j = 0; j < rin->getLx(); j++, pixin++, pixout++) { if (!(pixout->getTone() == 255 && pixout->getPaint() == 0 && pixin->m == 255)) continue; std::map<TPixel, int>::const_iterator it; int paintIndex; if ((it = m_colorMap.find(*pixin)) == m_colorMap.end()) { if (m_colorTolerance > 0) it = findNearestColor(*pixin); // if (it==colorMap.end() && (int)colorMap.size()>origColorCount) //se non l'ho trovato tra i colori origari, lo cerco in quelli nuovi, ma in questo caso deve essere esattamente uguale(tolerance = 0) // it = findNearestColor(*pixin, colorMap, colorTolerance, origColorCount, colorMap.size()-1); if (it == m_colorMap.end() && m_lastIndex < 4096) { m_colorMap[*pixin] = ++m_lastIndex; paintIndex = m_lastIndex; } else if (it != m_colorMap.end()) { m_colorMap[*pixin] = it->second; paintIndex = it->second; } } else paintIndex = it->second; FillParameters params; params.m_p = TPoint(j, i); params.m_styleId = paintIndex; params.m_emptyOnly = true; fill(rout, params); //if (*((ULONG *)rout->getRawData())!=0xff) // { // int cavolo=0; // } } } //seconda passata: se son rimasti pixel antialiasati non fillati, si fillano, cercando nelle vicinanze un pixel di paint puro per capire il colore da usare for (int i = 0; i < rin->getLy(); i++) { TPixel *pixin = rin->pixels(i); TPixelCM32 *pixout = rout->pixels(i); for (int j = 0; j < rin->getLx(); j++, pixin++, pixout++) { if (!(pixout->getTone() > 0 && pixout->getTone() < 255 && pixout->getPaint() == 0 && pixin->m == 255)) continue; TPoint p = getClosestPurePaint(rout, i, j); if (p.x == -1) continue; //pixout->setPaint( paintIndex); FillParameters params; params.m_p = TPoint(j, i); params.m_styleId = (rout->pixels(p.y) + p.x)->getPaint(); params.m_emptyOnly = true; fill(rout, params); } } //infine, si filla di trasparente lo sfondo, percorrendo il bordo, nel caso di trasbordamenti di colore TPixelCM32 *pixCm; TPixel *pix; pixCm = rout->pixels(0); pix = rin->pixels(0); FillParameters params; params.m_styleId = 0; for (int i = 0; i < rout->getLx(); i++, pixCm++, pix++) if (pixCm->getTone() == 255 && pixCm->getPaint() != 0 && pix->m == 0) { params.m_p = TPoint(i, 0); fill(rout, params); } pixCm = rout->pixels(rout->getLy() - 1); pix = rin->pixels(rout->getLy() - 1); for (int i = 0; i < rout->getLx(); i++, pixCm++, pix++) if (pixCm->getTone() == 255 && pixCm->getPaint() != 0 && pix->m == 0) { params.m_p = TPoint(i, rout->getLy() - 1); fill(rout, params); } int wrapCM = rout->getWrap(); int wrap = rin->getWrap(); pixCm = rout->pixels(0); pix = rin->pixels(0); for (int i = 0; i < rin->getLy(); i++, pixCm += wrapCM, pix += wrap) if (pixCm->getTone() == 255 && pixCm->getPaint() != 0 && pix->m == 0) { params.m_p = TPoint(0, i); fill(rout, params); } pixCm = rout->pixels(0) + rout->getLx() - 1; pix = rin->pixels(0) + rin->getLx() - 1; for (int i = 0; i < rin->getLy(); i++, pixCm += wrapCM, pix += wrap) if (pixCm->getTone() == 255 && pixCm->getPaint() != 0 && pix->m == 0) { params.m_p = TPoint(rout->getLx() - 1, i); fill(rout, params); } }