QRect KisRasterKeyframeChannel::affectedRect(KisKeyframeSP key)
{
    KeyframesMap::iterator it = keys().find(key->time());
    QRect rect;

    // Calculate changed area as the union of the current and previous keyframe.
    // This makes sure there are no artifacts left over from the previous frame
    // where the new one doesn't cover the area.

    if (it == keys().begin()) {
        // Using the *next* keyframe at the start of the timeline avoids artifacts
        // when deleting or moving the first key
        it++;
    } else {
        it--;
    }

    if (it != keys().end()) {
        rect = m_d->paintDevice->framesInterface()->frameBounds(it.value()->value());
    }

    rect |= m_d->paintDevice->framesInterface()->frameBounds(key->value());

    if (m_d->onionSkinsEnabled) {
        const QRect dirtyOnionSkinsRect =
            KisOnionSkinCompositor::instance()->calculateFullExtent(m_d->paintDevice);
        rect |= dirtyOnionSkinsRect;
    }

    return rect;
}
KisKeyframeSP KisRasterKeyframeChannel::loadKeyframe(const QDomElement &keyframeNode)
{
    int time = keyframeNode.attribute("time").toUInt();

    QPoint offset;
    KisDomUtils::loadValue(keyframeNode, "offset", &offset);
    QString frameFilename = keyframeNode.attribute("frame");

    KisKeyframeSP keyframe;

    if (m_d->frameFilenames.isEmpty()) {
        // First keyframe loaded: use the existing frame

        Q_ASSERT(keyframeCount() == 1);
        keyframe = constKeys().begin().value();

        // Remove from keys. It will get reinserted with new time once we return
        keys().remove(keyframe->time());

        keyframe->setTime(time);
        m_d->paintDevice->move(offset);
    } else {
        KUndo2Command tempCommand;
        int frameId = m_d->paintDevice->framesInterface()->createFrame(false, 0, offset, &tempCommand);

        keyframe = toQShared(new KisKeyframe(this, time, frameId));
    }

    setFrameFilename(keyframe->value(), frameFilename);

    return keyframe;
}
void KisRasterKeyframeChannel::importFrame(int time, KisPaintDeviceSP sourceDevice, KUndo2Command *parentCommand)
{
    KisKeyframeSP keyframe = addKeyframe(time, parentCommand);

    const int frameId = keyframe->value();

    m_d->paintDevice->framesInterface()->uploadFrame(frameId, sourceDevice);
}
void KisScalarKeyframeChannel::destroyKeyframe(KisKeyframeSP key, KUndo2Command *parentCommand)
{
    int index = key->value();

    KIS_ASSERT_RECOVER_RETURN(m_d->values.contains(index));

    KUndo2Command *cmd = new Private::InsertValueCommand(m_d.data(), index, m_d->values[index], false, parentCommand);
    cmd->redo();
}
KisKeyframeSP KisRasterKeyframeChannel::createKeyframe(int time, const KisKeyframeSP copySrc, KUndo2Command *parentCommand)
{
    int srcFrame = (copySrc != 0) ? copySrc->value() : 0;

    int frameId = m_d->paintDevice->framesInterface()->createFrame((copySrc != 0), srcFrame, QPoint(), parentCommand);

    KisKeyframeSP keyframe(new KisKeyframe(this, time, (quint32)frameId));

    return keyframe;
}
void KisScalarKeyframeChannel::setScalarValue(KisKeyframeSP keyframe, qreal value, KUndo2Command *parentCommand)
{
    QScopedPointer<KUndo2Command> tempCommand;
    if (!parentCommand) {
        tempCommand.reset(new KUndo2Command());
        parentCommand = tempCommand.data();
    }

    int index = keyframe->value();
    KUndo2Command *cmd = new Private::SetValueCommand(m_d.data(), index, m_d->values[index], value, parentCommand);
    cmd->redo();
}
Esempio n. 7
0
bool KisAnimationCurvesModel::adjustKeyframes(const QModelIndexList &indexes, int timeOffset, qreal valueOffset)
{
    KUndo2Command *command = new KUndo2Command(
        kundo2_i18np("Adjust Keyframe",
                     "Adjust %1 Keyframes",
                     indexes.size()));

    if (timeOffset != 0) {
        bool ok = offsetFrames(indexes, QPoint(timeOffset, 0), false, command);
        if (!ok) return false;
    }

    Q_FOREACH(QModelIndex oldIndex, indexes) {
        KisScalarKeyframeChannel *channel = m_d->getCurveAt(oldIndex)->channel();
        KIS_ASSERT_RECOVER_RETURN_VALUE(channel, false);

        KisKeyframeSP keyframe = channel->keyframeAt(oldIndex.column() + timeOffset);
        KIS_ASSERT_RECOVER_RETURN_VALUE(!keyframe.isNull(), false);

        qreal currentValue = channel->scalarValue(keyframe);
        channel->setScalarValue(keyframe, currentValue + valueOffset, command);
    };
void KisRasterKeyframeChannel::uploadExternalKeyframe(KisKeyframeChannel *srcChannel, int srcTime, KisKeyframeSP dstFrame)
{
    KisRasterKeyframeChannel *srcRasterChannel = dynamic_cast<KisRasterKeyframeChannel*>(srcChannel);
    KIS_ASSERT_RECOVER_RETURN(srcRasterChannel);

    const int srcId = srcRasterChannel->frameIdAt(srcTime);
    const int dstId = dstFrame->value();

    m_d->paintDevice->framesInterface()->
        uploadFrame(srcId,
                    dstId,
                    srcRasterChannel->m_d->paintDevice);
}
void KisRasterKeyframeChannel::saveKeyframe(KisKeyframeSP keyframe, QDomElement keyframeElement, const QString &layerFilename)
{
    int frameId = keyframe->value();

    QString filename = frameFilename(frameId);
    if (filename.isEmpty()) {
        filename = chooseFrameFilename(frameId, layerFilename);
    }
    keyframeElement.setAttribute("frame", filename);

    QPoint offset = m_d->paintDevice->framesInterface()->frameOffset(frameId);
    KisDomUtils::saveValue(&keyframeElement, "offset", offset);
}
void KisScalarKeyframeChannel::uploadExternalKeyframe(KisKeyframeChannel *srcChannel, int srcTime, KisKeyframeSP dstFrame)
{
    KisScalarKeyframeChannel *srcScalarChannel = dynamic_cast<KisScalarKeyframeChannel*>(srcChannel);
    KIS_ASSERT_RECOVER_RETURN(srcScalarChannel);

    KisKeyframeSP srcFrame = srcScalarChannel->keyframeAt(srcTime);
    KIS_ASSERT_RECOVER_RETURN(srcFrame);

    const qreal newValue = scalarValue(srcFrame);

    const int dstId = dstFrame->value();
    KIS_ASSERT_RECOVER_RETURN(m_d->values.contains(dstId));
    m_d->values[dstId] = newValue;
}
void KisRasterKeyframeChannel::fetchFrame(KisKeyframeSP keyframe, KisPaintDeviceSP targetDevice)
{
    m_d->paintDevice->framesInterface()->fetchFrame(keyframe->value(), targetDevice);
}
int KisRasterKeyframeChannel::frameIdAt(int time) const
{
    KisKeyframeSP key = activeKeyframeAt(time);
    return key->value();
}
void KisScalarKeyframeChannel::saveKeyframe(KisKeyframeSP keyframe, QDomElement keyframeElement, const QString &layerFilename)
{
    Q_UNUSED(layerFilename);
    keyframeElement.setAttribute("value", m_d->values[keyframe->value()]);
}
void KisRasterKeyframeChannel::destroyKeyframe(KisKeyframeSP key, KUndo2Command *parentCommand)
{
    m_d->paintDevice->framesInterface()->deleteFrame(key->value(), parentCommand);
}
qreal KisScalarKeyframeChannel::scalarValue(const KisKeyframeSP keyframe) const
{
    return m_d->values[keyframe->value()];
}
Esempio n. 16
0
QVariant KisAnimationCurvesModel::data(const QModelIndex &index, int role) const
{
    KisAnimationCurve *curve = m_d->getCurveAt(index);

    if (curve) {
        KisScalarKeyframeChannel *channel = curve->channel();

        int time = index.column();
        KisKeyframeSP keyframe = channel->keyframeAt(time);

        switch (role) {
        case SpecialKeyframeExists:
            return !keyframe.isNull();
        case ScalarValueRole:
            return channel->interpolatedValue(time);
        case LeftTangentRole:
            return (keyframe.isNull()) ? QVariant() : keyframe->leftTangent();
        case RightTangentRole:
            return (keyframe.isNull()) ? QVariant() : keyframe->rightTangent();
        case InterpolationModeRole:
            return (keyframe.isNull()) ? QVariant() : keyframe->interpolationMode();
        case TangentsModeRole:
            return (keyframe.isNull()) ? QVariant() : keyframe->tangentsMode();
        case CurveColorRole:
            return curve->color();
        case CurveVisibleRole:
            return curve->visible();
        case PreviousKeyframeTime:
        {
            KisKeyframeSP active = channel->activeKeyframeAt(time);
            if (active.isNull()) return QVariant();
            if (active->time() < time) {
                return active->time();
            }
            KisKeyframeSP previous = channel->previousKeyframe(active);
            if (previous.isNull()) return QVariant();
            return previous->time();
        }
        case NextKeyframeTime:
        {
            KisKeyframeSP active = channel->activeKeyframeAt(time);
            if (active.isNull()) {
                KisKeyframeSP first = channel->firstKeyframe();
                if (!first.isNull() && first->time() > time) {
                    return first->time();
                }
                return QVariant();
            }
            KisKeyframeSP next = channel->nextKeyframe(active);
            if (next.isNull()) return QVariant();
            return next->time();
        }
        default:
            break;
        }
    }

    return KisTimeBasedItemModel::data(index, role);
}
Esempio n. 17
0
bool KisAnimationCurvesModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (!index.isValid()) return false;
    KisScalarKeyframeChannel *channel = m_d->getCurveAt(index)->channel();
    KUndo2Command *command = m_d->undoCommand;

    switch (role) {
    case ScalarValueRole:
    {
        KisKeyframeSP keyframe = channel->keyframeAt(index.column());
        if (keyframe) {
            if (!command) command = new KUndo2Command(kundo2_i18n("Adjust keyframe"));
            channel->setScalarValue(keyframe, value.toReal(), command);
        } else {
            if (!command) command = new KUndo2Command(kundo2_i18n("Insert keyframe"));
            auto *addKeyframeCommand = new KisScalarKeyframeChannel::AddKeyframeCommand(
                channel, index.column(), value.toReal(), command);
            addKeyframeCommand->redo();
        }
    }
        break;
    case LeftTangentRole:
    case RightTangentRole:
    {
        KisKeyframeSP keyframe = channel->keyframeAt(index.column());
        if (!keyframe) return false;

        QPointF leftTangent = (role == LeftTangentRole ? value.toPointF() : keyframe->leftTangent());
        QPointF rightTangent = (role == RightTangentRole ? value.toPointF() : keyframe->rightTangent());

        if (!command) command = new KUndo2Command(kundo2_i18n("Adjust tangent"));
        channel->setInterpolationTangents(keyframe, keyframe->tangentsMode(), leftTangent, rightTangent, command);
    }
        break;
    case InterpolationModeRole:
    {
        KisKeyframeSP keyframe = channel->keyframeAt(index.column());
        if (!keyframe) return false;

        if (!command) command = new KUndo2Command(kundo2_i18n("Set interpolation mode"));
        channel->setInterpolationMode(keyframe, (KisKeyframe::InterpolationMode)value.toInt(), command);
    }
        break;
    case TangentsModeRole:
    {
        KisKeyframeSP keyframe = channel->keyframeAt(index.column());
        if (!keyframe) return false;

        KisKeyframe::InterpolationTangentsMode mode = (KisKeyframe::InterpolationTangentsMode)value.toInt();
        QPointF leftTangent = keyframe->leftTangent();
        QPointF rightTangent = keyframe->rightTangent();

        if (!command) command = new KUndo2Command(kundo2_i18n("Set interpolation mode"));
        channel->setInterpolationTangents(keyframe, mode, leftTangent, rightTangent, command);
    }
        break;
    default:
        return KisTimeBasedItemModel::setData(index, value, role);
    }

    if (command && !m_d->undoCommand) {
        image()->postExecutionUndoAdapter()->addCommand(toQShared(command));
    }

    return true;
}
QRect KisRasterKeyframeChannel::frameExtents(KisKeyframeSP keyframe)
{
    return m_d->paintDevice->framesInterface()->frameBounds(keyframe->value());
}
Esempio n. 19
0
KisImageBuilder_Result CSVSaver::encode(const QUrl &uri,const QString &filename)
{
    int idx;
    int start, end;
    KisNodeSP node;
    QByteArray ba;
    KisKeyframeSP keyframe;
    QVector<CSVLayerRecord*> layers;

    KisImageAnimationInterface *animation = m_image->animationInterface();

    //open the csv file for writing
    QFile f(uri.toLocalFile());
    if (!f.open(QIODevice::WriteOnly)) {
        return KisImageBuilder_RESULT_NOT_LOCAL;
    }

    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));

    //DataStream instead of TextStream for correct line endings
    QDataStream stream(&f);

    QString path = filename;

    if (path.right(4).toUpper() == ".CSV")
        path = path.left(path.size() - 4);

    path.append(".frames");

    //create directory

    QDir dir(path);
    if (!dir.exists()) {
        dir.mkpath(".");
    }
    //according to the QT docs, the slash is a universal directory separator
    path.append("/");

    m_image->lock();
    node = m_image->rootLayer()->firstChild();

    //TODO: correct handling of the layer tree.
    //for now, only top level paint layers are saved

    idx = 0;

    while (node) {
        if (node->inherits("KisPaintLayer")) {
            KisPaintLayer* paintLayer = dynamic_cast<KisPaintLayer*>(node.data());
            CSVLayerRecord* layerRecord = new CSVLayerRecord();
            layers.prepend(layerRecord); //reverse order!

            layerRecord->name = paintLayer->name();
            layerRecord->name.replace(QRegExp("[\"\\r\\n]"), "_");

            if (layerRecord->name.isEmpty())
                layerRecord->name= QString("Unnamed-%1").arg(idx);

            layerRecord->visible = (paintLayer->visible()) ? 1 : 0;
            layerRecord->density = (float)(paintLayer->opacity()) / OPACITY_OPAQUE_U8;
            layerRecord->blending = convertToBlending(paintLayer->compositeOpId());
            layerRecord->layer = paintLayer;
            layerRecord->channel = paintLayer->projection()->keyframeChannel();
            layerRecord->last = "";
            layerRecord->frame = 0;
            idx++;
        }
        node = node->nextSibling();
    }

    KisTimeRange range = animation->fullClipRange();

    start = (range.isValid()) ? range.start() : 0;

    if (!range.isInfinite()) {
        end = range.end();

        if (end < start) end = start;
    } else {
        //undefined length, searching for the last keyframe
        end = start;

        for (idx = 0; idx < layers.size(); idx++) {
            keyframe = layers.at(idx)->channel->lastKeyframe();

            if ( (!keyframe.isNull()) && (keyframe->time() > end) )
                end = keyframe->time();
        }
    }

    //create temporary doc for exporting
    QScopedPointer<KisDocument> exportDoc(KisPart::instance()->createDocument());
    createTempImage(exportDoc.data());

    KisImageBuilder_Result retval= KisImageBuilder_RESULT_OK;

    if (!m_batchMode) {
        emit m_doc->statusBarMessage(i18n("Saving CSV file..."));
        emit m_doc->sigProgress(0);
        connect(m_doc, SIGNAL(sigProgressCanceled()), this, SLOT(cancel()));
    }
    int frame = start;
    int step = 0;

    do {
        qApp->processEvents();

        if (m_stop) {
            retval = KisImageBuilder_RESULT_CANCEL;
            break;
        }

        switch(step) {

        case 0 :    //first row
            if (f.write("UTF-8, TVPaint, \"CSV 1.0\"\r\n") < 0) {
                retval = KisImageBuilder_RESULT_FAILURE;
            }
            break;

        case 1 :    //scene header names
            if (f.write("Project Name, Width, Height, Frame Count, Layer Count, Frame Rate, Pixel Aspect Ratio, Field Mode\r\n") < 0) {
                retval = KisImageBuilder_RESULT_FAILURE;
            }
            break;

        case 2 :    //scene header values
            ba = QString("\"%1\", ").arg(m_image->objectName()).toUtf8();
            if (f.write(ba.data()) < 0) {
                retval = KisImageBuilder_RESULT_FAILURE;
                break;
            }
            ba = QString("%1, %2, ").arg(m_image->width()).arg(m_image->height()).toUtf8();
            if (f.write(ba.data()) < 0) {
                retval = KisImageBuilder_RESULT_FAILURE;
                break;
            }

            ba = QString("%1, %2, ").arg(end - start + 1).arg(layers.size()).toUtf8();
            if (f.write(ba.data()) < 0) {
                retval = KisImageBuilder_RESULT_FAILURE;
                break;
            }
            //the framerate is an integer here
            ba = QString("%1, ").arg((double)(animation->framerate()),0,'f',6).toUtf8();
            if (f.write(ba.data()) < 0) {
                retval = KisImageBuilder_RESULT_FAILURE;
                break;
            }
            ba = QString("%1, Progressive\r\n").arg((double)(m_image->xRes() / m_image->yRes()),0,'f',6).toUtf8();
            if (f.write(ba.data()) < 0) {
                retval = KisImageBuilder_RESULT_FAILURE;
                break;
            }
            break;

        case 3 :    //layer header values
            if (f.write("#Layers") < 0) {          //Layers
                retval = KisImageBuilder_RESULT_FAILURE;
                break;
            }

            for (idx = 0; idx < layers.size(); idx++) {
                ba = QString(", \"%1\"").arg(layers.at(idx)->name).toUtf8();
                if (f.write(ba.data()) < 0)
                    break;
            }
            break;

        case 4 :
            if (f.write("\r\n#Density") < 0) {     //Density
                retval = KisImageBuilder_RESULT_FAILURE;
                break;
            }
            for (idx = 0; idx < layers.size(); idx++) {
                ba = QString(", %1").arg((double)(layers.at(idx)->density), 0, 'f', 6).toUtf8();
                if (f.write(ba.data()) < 0)
                    break;
            }
            break;

        case 5 :
            if (f.write("\r\n#Blending") < 0) {     //Blending
                retval = KisImageBuilder_RESULT_FAILURE;
                break;
            }
            for (idx = 0; idx < layers.size(); idx++) {
                ba = QString(", \"%1\"").arg(layers.at(idx)->blending).toUtf8();
                if (f.write(ba.data()) < 0)
                    break;
            }
            break;

        case 6 :
            if (f.write("\r\n#Visible") < 0) {     //Visible
                retval = KisImageBuilder_RESULT_FAILURE;
                break;
            }
            for (idx = 0; idx < layers.size(); idx++) {
                ba = QString(", %1").arg(layers.at(idx)->visible).toUtf8();
                if (f.write(ba.data()) < 0)
                    break;
            }
            if (idx < layers.size()) {
                retval = KisImageBuilder_RESULT_FAILURE;
            }
            break;

        default :    //frames

            if (frame > end) {
                if (f.write("\r\n") < 0)
                    retval = KisImageBuilder_RESULT_FAILURE;

                step = 8;
                break;
            }

            ba = QString("\r\n#%1").arg(frame, 5, 10, QChar('0')).toUtf8();
            if (f.write(ba.data()) < 0) {
                retval = KisImageBuilder_RESULT_FAILURE;
                break;
            }

            for (idx = 0; idx < layers.size(); idx++) {
                CSVLayerRecord *layer = layers.at(idx);
                keyframe = layer->channel->keyframeAt(frame);

                if (!keyframe.isNull()) {
                    if (!m_batchMode) {
                        emit m_doc->sigProgress(((frame - start) * layers.size() + idx) * 100 /
                                                ((end - start) * layers.size()));
                    }
                    retval = getLayer(layer, exportDoc.data(), keyframe, path, frame, idx);

                    if (retval != KisImageBuilder_RESULT_OK)
                        break;
                }
                ba = QString(", \"%1\"").arg(layer->last).toUtf8();

                if (f.write(ba.data()) < 0)
                    break;
            }
            if (idx < layers.size())
                retval = KisImageBuilder_RESULT_FAILURE;

            frame++;
            step = 6; //keep step here
            break;
        }
        step++;
    } while((retval == KisImageBuilder_RESULT_OK) && (step < 8));

    m_image->unlock();

    qDeleteAll(layers);
    f.close();

    if (!m_batchMode) {
        disconnect(m_doc, SIGNAL(sigProgressCanceled()), this, SLOT(cancel()));
        emit m_doc->sigProgress(100);
        emit m_doc->clearStatusBarMessage();
    }
    QApplication::restoreOverrideCursor();
    return retval;
}