/* * scribiu -- read notebooks and voice memos from Livescribe pens * Copyright (C) 2021 Javier S. Pedro * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "stfexporter.h" #define XMLNS_INK "http://www.w3.org/2003/InkML" class StfToTXYP : public StfReader::StrokeHandler { QTextStream _out; qint64 _startTime; bool _relativeTime; public: StfToTXYP(QIODevice *out, bool relativeTime) : _out(out), _startTime(0), _relativeTime(relativeTime) { _out << "T\tX\tY\tP\n"; } bool startStroke(const QPoint& p, int force, qint64 time) { if (_relativeTime && _startTime == 0) { _startTime = time; } _out << (time - _startTime) << '\t' << p.x() << '\t' << p.y() << '\t' << force << '\n'; return true; } bool strokePoint(const QPoint& p, int force, qint64 time) { _out << (time - _startTime) << '\t' << p.x() << '\t' << p.y() << '\t' << force << '\n'; return true; } bool endStroke(qint64 time) { // Force == 0 is used to detect strokes Q_UNUSED(time); return true; } }; class StfToInkML : public StfReader::StrokeHandler { QXmlStreamWriter *_out; QPoint _lastP; qint64 _startTime; public: StfToInkML(QXmlStreamWriter *out) : _out(out), _lastP(), _startTime(0) { } bool startStroke(const QPoint& p, int force, qint64 time) { Q_UNUSED(force); if (_startTime == 0) { _startTime = time; } _out->writeStartElement(XMLNS_INK, "trace"); _out->writeAttribute("timeOffset", QString::number(time - _startTime)); _out->writeCharacters(QString("%1 %2").arg(p.x()).arg(p.y())); _lastP = p; return true; } bool strokePoint(const QPoint& p, int force, qint64 time) { Q_UNUSED(force); Q_UNUSED(time); QPoint delta = p - _lastP; _out->writeCharacters(QString(", %1 %2").arg(delta.x()).arg(delta.y())); _lastP = p; return true; } bool endStroke(qint64 time) { Q_UNUSED(time); _out->writeEndElement(); return true; } }; StfExporter::StfExporter(AfdNotebook *nb) : _nb(nb) { } void StfExporter::exportToTXYP(QIODevice *out, int pageNum, bool relativeTime) { QStringList pens = _nb->penSerials(); if (pens.isEmpty()) return; StfToTXYP h(out, relativeTime); exportPage(&h, pageNum); } void StfExporter::exportToInkML(QIODevice *out, int pageNum) { QStringList pens = _nb->penSerials(); if (pens.isEmpty()) return; QXmlStreamWriter writer(out); writer.setAutoFormatting(true); writer.writeStartDocument(); writer.writeDefaultNamespace(XMLNS_INK); writer.writeStartElement(XMLNS_INK, "ink"); #if 0 /* No need to write out inkSource element, since default trace format is OK for now */ writer.writeStartElement(XMLNS_INK, "inkSource"); writer.writeAttribute("manufacturer", "Livescribe"); writer.writeAttribute("description", "Dumped by Scribiu"); writer.writeStartElement(XMLNS_INK, "traceFormat"); writer.writeEmptyElement(XMLNS_INK, "channel"); writer.writeAttribute("name", "X"); writer.writeAttribute("type", "integer"); writer.writeEmptyElement(XMLNS_INK, "channel"); writer.writeAttribute("name", "Y"); writer.writeAttribute("type", "integer"); writer.writeEndElement(); writer.writeEmptyElement(XMLNS_INK, "sampleRate"); writer.writeAttribute("uniform", "true"); writer.writeAttribute("value", "75"); writer.writeEndElement(); #endif StfToInkML h(&writer); exportPage(&h, pageNum); writer.writeEndElement(); writer.writeEndDocument(); } bool StfExporter::exportPage(StfReader::StrokeHandler *handler, int pageNum) { QStringList pens = _nb->penSerials(); if (pens.isEmpty()) return true; // No pen wrote on this page StfReader r; r.setStrokeHandler(handler); foreach (const QString &pen, pens) { QStringList strokeFiles = _nb->strokeFiles(pen, pageNum); foreach (const QString &strokeFile, strokeFiles) { QFile in(strokeFile); if (!in.open(QIODevice::ReadOnly)) { qWarning() << "Could not open stroke file:" << strokeFile; continue; } if (!r.parse(&in)) { qWarning() << "Could not parse stroke file:" << strokeFile; continue; } } } return true; }