QVector<QPolygon> KisOutlineGenerator::outlineImpl(typename StorageStrategy::StorageType buffer,
                                                   qint32 xOffset, qint32 yOffset,
                                                   qint32 width, qint32 height)
{
    QVector<QPolygon> paths;

    try {
        StorageStrategy storage(buffer, width, height, m_cs->pixelSize());

        for (qint32 y = 0; y < height; y++) {
            for (qint32 x = 0; x < width; x++) {

                if (m_cs->opacityU8(storage.pickPixel(x, y)) == m_defaultOpacity)
                    continue;

                EdgeType startEdge = TopEdge;

                EdgeType edge = startEdge;
                while (edge != NoEdge &&
                       (*storage.pickMark(x, y) & (1 << edge) ||
                        !isOutlineEdge(storage, edge, x, y, width, height))) {

                    edge = nextEdge(edge);
                    if (edge == startEdge)
                        edge = NoEdge;
                }

                if (edge != NoEdge) {
                    QPolygon path;
                    path << QPoint(x + xOffset, y + yOffset);

                    bool clockwise = edge == BottomEdge;

                    qint32 row = y, col = x;
                    EdgeType currentEdge = edge;
                    EdgeType lastEdge = currentEdge;

                    forever {
                        //While following a straight line no points need to be added
                        if (lastEdge != currentEdge) {
                            appendCoordinate(&path, col + xOffset, row + yOffset, currentEdge);
                            lastEdge = currentEdge;
                        }

                        *storage.pickMark(col, row) |= 1 << currentEdge;
                        nextOutlineEdge(storage, &currentEdge, &row, &col, width, height);

                        if (row == y && col == x && currentEdge == edge) {
                            // add last point of the polygon
                            appendCoordinate(&path, col + xOffset, row + yOffset, currentEdge);
                            break;
                        }
                    }

                    if(!m_simple || !clockwise)
                        paths.push_back(path);
                }
            }
        }
    }
    catch(std::bad_alloc) {
        warnKrita << "KisOutlineGenerator::outline ran out of memory allocating " <<  width << "*" << height << "marks";
    }

    return paths;
}
Example #2
0
QVector<QPolygon> KisPixelSelection::outline()
{
    quint8 defaultPixel = *(m_datamanager->defaultPixel());
    QRect selectionExtent = exactBounds();
    qint32 xOffset = selectionExtent.x();
    qint32 yOffset = selectionExtent.y();
    qint32 width = selectionExtent.width();
    qint32 height = selectionExtent.height();

    quint8* buffer = new quint8[width*height];
    quint8* marks = new quint8[width*height];
    for (int i = 0; i < width*height; i++) {
        marks[i] = 0;
    }
    QVector<QPolygon> paths;

    readBytes(buffer, xOffset, yOffset, width, height);

    int nodes = 0;
    for (qint32 y = 0; y < height; y++) {
        for (qint32 x = 0; x < width; x++) {

            if (buffer[y*width+x] == defaultPixel)
                continue;

            EdgeType startEdge = TopEdge;

            EdgeType edge = startEdge;
            while (edge != NoEdge && (marks[y*width+x] & (1 << edge) || !isOutlineEdge(edge, x, y, buffer, width, height))) {
                edge = nextEdge(edge);
                if (edge == startEdge)
                    edge = NoEdge;
            }

            if (edge != NoEdge) {
                QPolygon path;
                path << QPoint(x + xOffset, y + yOffset);

// XXX: Unused? (BSAR)
//                bool clockwise = edge == BottomEdge;

                qint32 row = y, col = x;
                EdgeType currentEdge = edge;
                EdgeType lastEdge = currentEdge;
                do {
                    //While following a strait line no points nead to be added
                    if (lastEdge != currentEdge) {
                        appendCoordinate(&path, col + xOffset, row + yOffset, currentEdge);
                        nodes++;
                        lastEdge = currentEdge;
                    }

                    marks[row*width+col] |= 1 << currentEdge;
                    nextOutlineEdge(&currentEdge, &row, &col, buffer, width, height);
                } while (row != y || col != x || currentEdge != edge);

                paths.push_back(path);
            }
        }
    }
    delete[] buffer;
    delete[] marks;

    return paths;
}