| |
| |
|
|
| |
| |
| |
| |
| RasterStrokeGenerator::RasterStrokeGenerator(const TRasterCM32P &raster, Tasks task, ColorType colorType, |
| int styleId, const TThickPoint &p, bool selective, int selectedStyle, bool keepAntialias) |
| : m_raster(raster), m_boxOfRaster(TRect(raster->getSize())), m_styleId(styleId), m_selective(selective), m_task(task), m_colorType(colorType), m_eraseStyle(4095), m_selectedStyle(selectedStyle), m_keepAntiAlias(keepAntialias), m_doAnArc(false) |
| { |
| TThickPoint pp = p; |
| m_points.push_back(pp); |
| if (task == ERASE) |
| m_styleId = m_eraseStyle; |
| } |
| |
| |
| |
| RasterStrokeGenerator::~RasterStrokeGenerator() |
| { |
| } |
| |
| |
| |
| bool RasterStrokeGenerator::add(const TThickPoint &p) |
| { |
| TThickPoint pp = p; |
| TThickPoint mid((m_points.back() + pp) * 0.5, (p.thick + m_points.back().thick) * 0.5); |
| m_points.push_back(mid); |
| m_points.push_back(pp); |
| return true; |
| } |
| |
| |
| |
| |
| void RasterStrokeGenerator::generateStroke(bool isPencil) const |
| { |
| vector<TThickPoint> points(m_points); |
| int size = points.size(); |
| |
| TRect box = getBBox(points); |
| TPoint newOrigin = box.getP00(); |
| TRasterCM32P rasBuffer(box.getSize()); |
| rasBuffer->clear(); |
| |
| |
| translatePoints(points, newOrigin); |
| |
| vector<TThickPoint> partialPoints; |
| if (size == 1) { |
| rasterBrush(rasBuffer, points, m_styleId, !isPencil); |
| placeOver(m_raster, rasBuffer, newOrigin); |
| } else if (size <= 3) { |
| vector<TThickPoint> partialPoints; |
| partialPoints.push_back(points[0]); |
| partialPoints.push_back(points[1]); |
| rasterBrush(rasBuffer, partialPoints, m_styleId, !isPencil); |
| placeOver(m_raster, rasBuffer, newOrigin); |
| } else if (size % 2 == 1) |
| { |
| int strokeCount = (size - 1) / 2 - 1; |
| vector<TThickPoint> partialPoints; |
| partialPoints.push_back(points[0]); |
| partialPoints.push_back(points[1]); |
| rasterBrush(rasBuffer, partialPoints, m_styleId, !isPencil); |
| placeOver(m_raster, rasBuffer, newOrigin); |
| for (int i = 0; i < strokeCount; i++) { |
| partialPoints.clear(); |
| rasBuffer->clear(); |
| partialPoints.push_back(points[i * 2 + 1]); |
| partialPoints.push_back(points[i * 2 + 2]); |
| partialPoints.push_back(points[i * 2 + 3]); |
| if (i == strokeCount - 1) |
| partialPoints.push_back(points[i * 2 + 4]); |
| |
| rasterBrush(rasBuffer, partialPoints, m_styleId, !isPencil); |
| placeOver(m_raster, rasBuffer, newOrigin); |
| } |
| } else { |
| vector<TThickPoint> partialPoints; |
| partialPoints.push_back(points[0]); |
| partialPoints.push_back(points[1]); |
| rasterBrush(rasBuffer, partialPoints, m_styleId, !isPencil); |
| placeOver(m_raster, rasBuffer, newOrigin); |
| if (size > 2) { |
| partialPoints.clear(); |
| vector<TThickPoint>::iterator it = points.begin(); |
| it++; |
| partialPoints.insert(partialPoints.begin(), it, points.end()); |
| rasterBrush(rasBuffer, partialPoints, m_styleId, !isPencil); |
| placeOver(m_raster, rasBuffer, newOrigin); |
| } |
| } |
| } |
| |
| |
| |
| TRect RasterStrokeGenerator::generateLastPieceOfStroke(bool isPencil, bool closeStroke) |
| { |
| vector<TThickPoint> points; |
| int size = m_points.size(); |
| |
| if (size == 3) { |
| points.push_back(m_points[0]); |
| points.push_back(m_points[1]); |
| } else if (size == 1) |
| points.push_back(m_points[0]); |
| else { |
| points.push_back(m_points[size - 4]); |
| points.push_back(m_points[size - 3]); |
| points.push_back(m_points[size - 2]); |
| if (closeStroke) |
| points.push_back(m_points[size - 1]); |
| } |
| |
| TRect box = getBBox(points); |
| TPoint newOrigin = box.getP00(); |
| TRasterCM32P rasBuffer(box.getSize()); |
| rasBuffer->clear(); |
| |
| |
| translatePoints(points, newOrigin); |
| |
| rasterBrush(rasBuffer, points, m_styleId, !isPencil); |
| placeOver(m_raster, rasBuffer, newOrigin); |
| return box; |
| } |
| |
| |
| |
| |
| TRect RasterStrokeGenerator::getBBox(const vector<TThickPoint> &points) const |
| { |
| double x0 = (std::numeric_limits<double>::max)(), y0 = (std::numeric_limits<double>::max)(), |
| x1 = -(std::numeric_limits<double>::max)(), y1 = -(std::numeric_limits<double>::max)(); |
| for (int i = 0; i < (int)points.size(); i++) { |
| double radius = points[i].thick * 0.5; |
| if (points[i].x - radius < x0) |
| x0 = points[i].x - radius; |
| if (points[i].x + radius > x1) |
| x1 = points[i].x + radius; |
| if (points[i].y - radius < y0) |
| y0 = points[i].y - radius; |
| if (points[i].y + radius > y1) |
| y1 = points[i].y + radius; |
| } |
| return TRect(TPoint((int)floor(x0 - 3), (int)floor(y0 - 3)), TPoint((int)ceil(x1 + 3), (int)ceil(y1 + 3))); |
| } |
| |
| |
| |
| |
| void RasterStrokeGenerator::translatePoints(vector<TThickPoint> &points, const TPoint &newOrigin) const |
| { |
| TPointD p(newOrigin.x, newOrigin.y); |
| for (int i = 0; i < (int)points.size(); i++) |
| points[i] -= p; |
| } |
| |
| |
| |
| |
| void RasterStrokeGenerator::placeOver(const TRasterCM32P &out, const TRasterCM32P &in, const TPoint &p) const |
| { |
| TRect inBox = in->getBounds() + p; |
| TRect outBox = out->getBounds(); |
| TRect box = inBox * outBox; |
| if (box.isEmpty()) |
| return; |
| TRasterCM32P rOut = out->extract(box); |
| TRect box2 = box - p; |
| TRasterCM32P rIn = in->extract(box2); |
| for (int y = 0; y < rOut->getLy(); y++) { |
| |
| if (m_task == FINGER && (y == 0 || y == rOut->getLy() - 1)) |
| continue; |
| |
| TPixelCM32 *inPix = rIn->pixels(y); |
| TPixelCM32 *outPix = rOut->pixels(y); |
| TPixelCM32 *outEnd = outPix + rOut->getLx(); |
| for (; outPix < outEnd; ++inPix, ++outPix) { |
| if (m_task == BRUSH) { |
| int inTone = inPix->getTone(); |
| int outTone = outPix->getTone(); |
| if (inPix->isPureInk() && !m_selective) { |
| *outPix = TPixelCM32(inPix->getInk(), outPix->getPaint(), inTone); |
| continue; |
| } |
| if (outPix->isPureInk() && m_selective) { |
| *outPix = TPixelCM32(outPix->getInk(), outPix->getPaint(), outTone); |
| continue; |
| } |
| if (inTone <= outTone) { |
| *outPix = TPixelCM32(inPix->getInk(), outPix->getPaint(), inTone); |
| } |
| } |
| if (m_task == ERASE) { |
| if (m_colorType == INK) { |
| if (!m_keepAntiAlias) { |
| if (inPix->getTone() == 0 && (!m_selective || (m_selective && outPix->getInk() == m_selectedStyle))) { |
| outPix->setTone(255); |
| } |
| } else if (inPix->getTone() < 255 && (!m_selective || (m_selective && outPix->getInk() == m_selectedStyle))) { |
| outPix->setTone(tmax(outPix->getTone(), 255 - inPix->getTone())); |
| } |
| } |
| if (m_colorType == PAINT) { |
| if (inPix->getTone() == 0 && (!m_selective || (m_selective && outPix->getPaint() == m_selectedStyle))) |
| outPix->setPaint(0); |
| } |
| if (m_colorType == INKNPAINT) { |
| if (inPix->getTone() < 255 && (!m_selective || (m_selective && outPix->getPaint() == m_selectedStyle))) |
| outPix->setPaint(0); |
| if (!m_keepAntiAlias) { |
| if (inPix->getTone() == 0 && (!m_selective || (m_selective && outPix->getInk() == m_selectedStyle))) { |
| outPix->setTone(255); |
| } |
| } else if (inPix->getTone() < 255 && (!m_selective || (m_selective && outPix->getInk() == m_selectedStyle))) { |
| outPix->setTone(tmax(outPix->getTone(), 255 - inPix->getTone())); |
| } |
| } |
| } else if (m_task == PAINTBRUSH) { |
| if (!inPix->isPureInk()) |
| continue; |
| bool changePaint = !m_selective || (m_selective && outPix->getPaint() == 0); |
| if (m_colorType == INK) |
| *outPix = TPixelCM32(inPix->getInk(), outPix->getPaint(), outPix->getTone()); |
| if (m_colorType == PAINT) |
| if (changePaint) |
| *outPix = TPixelCM32(outPix->getInk(), inPix->getInk(), outPix->getTone()); |
| if (m_colorType == INKNPAINT) |
| *outPix = TPixelCM32(inPix->getInk(), changePaint ? inPix->getInk() : outPix->getPaint(), outPix->getTone()); |
| } |
| |
| |
| else if (m_task == FINGER) { |
| |
| if (outPix == rOut->pixels(y) || outPix == outEnd - 1) |
| continue; |
| |
| int inkId = inPix->getInk(); |
| if (inkId == 0) |
| continue; |
| |
| TPixelCM32 *neighbourPixels[4]; |
| neighbourPixels[0] = outPix - 1; |
| neighbourPixels[1] = outPix + 1; |
| neighbourPixels[2] = outPix - rOut->getWrap(); |
| neighbourPixels[3] = outPix + rOut->getWrap(); |
| int count = 0; |
| int tone = outPix->getTone(); |
| |
| |
| if (!m_selective) { |
| |
| int minTone = tone; |
| for (int p = 0; p < 4; p++) { |
| |
| if (neighbourPixels[p]->getTone() < tone) { |
| count++; |
| if (neighbourPixels[p]->getTone() < minTone) |
| minTone = neighbourPixels[p]->getTone(); |
| } |
| } |
| |
| |
| if (count <= 2) |
| continue; |
| *outPix = TPixelCM32(inkId, outPix->getPaint(), minTone); |
| } |
| |
| else { |
| if (outPix->isPurePaint() || outPix->getInk() != inkId) |
| continue; |
| |
| |
| int maxTone = tone; |
| for (int p = 0; p < 4; p++) { |
| |
| if (neighbourPixels[p]->getInk() != inkId) { |
| count++; |
| maxTone = 255; |
| } else if (neighbourPixels[p]->getTone() > tone) { |
| count++; |
| if (neighbourPixels[p]->getTone() > maxTone) |
| maxTone = neighbourPixels[p]->getTone(); |
| } |
| } |
| |
| |
| if (count <= 2) |
| continue; |
| *outPix = TPixelCM32((maxTone == 255) ? 0 : inkId, outPix->getPaint(), maxTone); |
| } |
| } |
| } |
| } |
| } |
| |
| |
| |
| TRect RasterStrokeGenerator::getLastRect() const |
| { |
| vector<TThickPoint> points; |
| int size = m_points.size(); |
| |
| if (size == 3) { |
| points.push_back(m_points[0]); |
| points.push_back(m_points[1]); |
| } else if (size == 1) |
| points.push_back(m_points[0]); |
| else { |
| points.push_back(m_points[size - 4]); |
| points.push_back(m_points[size - 3]); |
| points.push_back(m_points[size - 2]); |
| points.push_back(m_points[size - 1]); |
| } |
| return getBBox(points); |
| } |
| |