Download raw (22.9 KB)
#include "command.h"
#include <QColor>
#include <QPen>
#include <QBrush>
#include <QDebug>
#include <QFont>
#include <QFile>
#include <QSvgRenderer>
#include <cmath>
#include <QLineF>
Command * Command::instance = 0;
Command::Command():
QObject(0)
{
coordAbsolute = true;
commands.insert("move", 2);
commands.insert("line", 2);
commands.insert("cubic", 6);
commands.insert("stroke", 4);
commands.insert("fill", 3);
commands.insert("close", 0);
commands.insert("end", 0);
commands.insert("transform", 6);
commands.insert("change", 2);
commands.insert("font", 4);
commands.insert("text", 1);
commands.insert("textblock", 3);
commands.insert("image", 1);
commands.insert("absolute", 1);
commands.insert("svg", 1);
commands.insert("svg-effect", 4);
commands.insert("svg-effect2", 5);
commands.insert("page-size", 2);
commands.insert("turn", 2);
commands.insert("var", 2);
commands.insert("rotate", 1);
commands.insert("save",0);
commands.insert("restore",0);
clearAlias();
connect(&imgWatcher, SIGNAL(fileChanged(QString)), this, SLOT(updateImgCache(QString)));
}
Command * Command::getInstance()
{
if(!instance)
instance = new Command;
return instance;
}
void Command::clearAlias()
{
alias.clear();
foreach(QString c, commands.keys())
alias.insert(c,c);
}
void Command::clearImageCache()
{
foreach(QString i, imgCache.keys())
imgWatcher.removePath(i);
imgCache.clear();
}
void Command::setAlias(const QString &key, const QString &val)
{
if(alias.contains(key))
alias[key] = val;
}
QString Command::getFromAlias(const QString &a) const
{
foreach(const QString& s, alias.keys())
{
QString av(alias.value(s));
// qDebug()<<"ALIAS"<<av << a;
if(av == a)
return s;
}
return QString();
}
bool Command::checkVars(const QVariantList &vars)
{
if(vars.isEmpty())
return false;
QString command(getFromAlias(vars.first().toString()));
if(commands.contains(command)
&& vars.count() - 1 >= commands.value(command))
return true;
return false;
}
void Command::highlightPre(QPointF& point)
{
QColor hcol(Qt::green);
painter->drawPath(painterPath);
point = painterPath.currentPosition();
painterPath = QPainterPath();
painterPath.moveTo(point);
painter->setPen(hcol);
painter->setBrush(QBrush(hcol));
}
void Command::highlightPost(QPointF& point)
{
painter->drawPath(painterPath);
point = painterPath.currentPosition();
painterPath = QPainterPath();
painterPath.moveTo(point);
}
double Command::number(QVariant v) const
{
if(varMap.contains(v.toString()))
return varMap.value(v.toString());
return v.toDouble();
}
void Command::Draw(const QVariantList &vars, bool higlight)
{
if(!checkVars(vars))
return;
QString command(getFromAlias(vars.first().toString()));
const QPointF curPos(painterPath.currentPosition());
if(command == QString("var"))
{
varMap.insert(vars.at(1).toString(), number(vars.at(2)));
}
else if(command == QString("move"))
{
QPointF target(number(vars.at(1)), number(vars.at(2)));
if(!coordAbsolute)
target = curPos + target;
if(higlight)
{
QPointF p0(curPos);
QPointF p1(target);
QLineF r(p0,p1);
foreach(QTransform t, transforms)
{
r = t.map(r);
}
highlightPath->moveTo(r.x1(),r.y1());
highlightPath->lineTo(r.x2(),r.y2());
QRectF targetRect(r.x2() - 4, r.y2() - 4, 8 , 8);
highlightPath->addEllipse(targetRect);
}
painterPath.moveTo(target);
}
else if(command == QString("line"))
{
QPointF target(number(vars.at(1)), number(vars.at(2)));
if(!coordAbsolute)
target = curPos + target;
if(higlight)
{
QPointF p0(curPos);
QPointF p1(target);
QLineF r(p0,p1);
foreach(QTransform t, transforms)
{
r = t.map(r);
}
highlightPath->moveTo(r.x1(),r.y1());
highlightPath->lineTo(r.x2(),r.y2());
}
painterPath.lineTo(target);
}
else if(command == QString("turn"))
{
QString angleStr(vars.at(1).toString());
double distance( number(vars.at(2)) );
int ec(painterPath.elementCount());
QPointF curPosMinus1(curPos);
if(ec > 1) // we want at least 2 points
{
curPosMinus1 = QPointF(painterPath.elementAt(ec - 2).x, painterPath.elementAt(ec - 2).y);
}
QLineF l1(curPosMinus1, curPos);
double startAngle(l1.angle());
double extra(0);
if(vars.count() > 3)
extra = number(vars.at(3));
bool process(true);
double angle(0);
if(angleStr == QString("s"))
angle = startAngle + extra;
else if(angleStr == QString("r"))
angle = startAngle + 270 + extra;
else if(angleStr == QString("b"))
angle = startAngle + 180 + extra;
else if(angleStr == QString("l"))
angle = startAngle + 90 + extra;
else
process = false;
if(process)
{
QLineF l2(curPos, QPointF(curPos.x() +1, 0));
l2.setLength(distance);
l2.setAngle(angle);
painterPath.lineTo(l2.p2());
}
}
else if(command == QString("cubic"))
{
QPointF target(number(vars.at(5)), number(vars.at(6)));
QPointF c1(number(vars.at(1)), number(vars.at(2)));
QPointF c2(number(vars.at(3)), number(vars.at(4)));
if(!coordAbsolute)
{
target = curPos + target;
c1 = c1 + curPos;
c2 = c2 + curPos;
}
if(higlight)
{
QPainterPath path;
path.moveTo(curPos);
path.lineTo(c1);
path.moveTo(curPos);
path.cubicTo(c1,c2,target);
// path.moveTo(p1);
path.lineTo(c2);
foreach(QTransform t, transforms)
{
path = t.map(path);
}
highlightPath->addPath(path);
}
painterPath.cubicTo(c1,c2,target);
}
else if(command == QString("fill"))
{
painter->drawPath(painterPath);
painterPath = QPainterPath();
painterPath.moveTo(curPos);
QColor c(vars.at(1).toInt(), vars.at(2).toInt(), vars.at(3).toInt());
if(vars.count() == 5)
c.setAlpha(vars.at(4).toInt());
painter->setBrush(c);
}
else if(command == QString("stroke"))
{
painter->drawPath(painterPath);
painterPath = QPainterPath();
painterPath.moveTo(curPos);
QColor c(vars.at(1).toInt(), vars.at(2).toInt(), vars.at(3).toInt());
if(vars.count() == 6)
c.setAlpha(vars.at(5).toInt());
double width(number(vars.at(4)));
painter->setPen(QPen(QBrush(c), width));
}
else if(command == QString("transform"))
{
painter->drawPath(painterPath);
painterPath = QPainterPath();
painterPath.moveTo(curPos);
QTransform t(number(vars.at(1)), number(vars.at(2)),
number(vars.at(3)), number(vars.at(4)),
number(vars.at(5)), number(vars.at(6)));
painter->setWorldTransform(t, true);
transforms << t;
}
else if(command == QString("rotate"))
{
painter->drawPath(painterPath);
painterPath = QPainterPath();
painterPath.moveTo(curPos);
QTransform t;
t.rotate(number(vars.at(1)));
painter->setWorldTransform(t, true);
transforms << t;
}
else if(command == QString("end"))
{
painter->drawPath(painterPath);
painterPath = QPainterPath();
}
else if(command == QString("close"))
{
painterPath.closeSubpath();
}
else if(command == QString("change"))
{
setAlias(vars.at(1).toString(), vars.at(2).toString());
emit namesChanged();
}
else if(command == QString("font"))
{
QStringList familyName;
for(int i(4); i < vars.count(); ++i)
{
familyName << vars.at(i).toString();
}
QFont f(familyName.join(" "));
f.setPointSizeF(number(vars.at(1)));
f.setWeight(vars.at(2).toInt());
f.setItalic(vars.at(3).toBool());
painter->setFont(f);
}
else if(command == QString("text"))
{
QRect res;
QString text;
bool first(true);
for(int i(1); i < vars.count(); ++i)
{
if(first)
{
first = false;
text += vars.at(i).toString();
}
else
text += QString(" ") + vars.at(i).toString();
}
painter->drawText(qRound(curPos.x()), qRound(curPos.y()), 99999, 99999, Qt::AlignLeft | Qt::AlignTop ,text , &res );
if(higlight)
{
QRectF r(res);
foreach(QTransform t, transforms)
{
r = t.mapRect(r);
}
highlightPath->addRect(r);
}
painterPath.moveTo(curPos.x(), res.bottom());
}
else if(command == QString("textblock"))
{
int width(number(vars.at(1)));
Qt::Alignment align(Qt::AlignLeft);
QString ua(vars.at(2).toString());
if(ua == QString("right"))
align = Qt::AlignRight;
else if(ua == QString("center"))
align = Qt::AlignCenter;
else if(ua == QString("justify"))
align = Qt::AlignJustify;
QRect res;
QString text;
bool first(true);
for(int i(3); i < vars.count(); ++i)
{
if(first)
{
first = false;
text += vars.at(i).toString();
}
else
text += QString(" ") + vars.at(i).toString();
}
painter->drawText(qRound(curPos.x()), qRound(curPos.y()), width, 99999, align | Qt::AlignTop | Qt::TextWordWrap , text , &res );
if(higlight)
{
QRectF r(res);
foreach(QTransform t, transforms)
{
r = t.mapRect(r);
}
highlightPath->addRect(r);
}
painterPath.moveTo(curPos.x(), res.bottom());
}
else if(command == QString("image")
&& !skipImages)
{
QString imgFile(vars.at(1).toString());
if(QFile::exists(imgFile))
{
QImage img;
if(imgCache.contains(imgFile))
img = imgCache.value(imgFile);
else
{
img.load(imgFile);
if(!img.isNull())
{
imgCache.insert(imgFile, img);
if(!imgWatcher.files().contains(imgFile))
imgWatcher.addPath(imgFile);
}
}
if(!img.isNull())
{
if(vars.count() >= 4)
{
painter->drawImage(painterPath.currentPosition(), img.scaled(vars.at(2).toInt(),vars.at(3).toInt()));
}
else
painter->drawImage(painterPath.currentPosition(), img);
if(higlight)
{
QRectF r;
QPointF curPos = painterPath.currentPosition();
if(vars.count() >= 4)
{
QImage simg(img.scaled(vars.at(2).toInt(),vars.at(3).toInt()));
r = QRectF(curPos.x(),curPos.y(),
simg.width(), simg.height());
}
else
r = QRectF(curPos.x(),curPos.y(),
img.width(), img.height());
foreach(QTransform t, transforms)
{
r = t.mapRect(r);
}
highlightPath->addRect(r);
}
}
}
}
else if(command == QString("absolute"))
{
coordAbsolute = vars.at(1).toBool();
}
else if(command == QString("page-size"))
{
emit changeSceneRect(number(vars.at(1)), number(vars.at(2)));
}
else if(command == QString("svg"))
{
QString svgfile(vars.at(1).toString());
if(QFile::exists(svgfile))
{
QSvgRenderer svgRdr(svgfile);
QRectF r(svgRdr.viewBoxF());
r.moveTo(curPos);
svgRdr.render(painter, r);
}
}
else if(command == QString("svg-effect"))
{
// @1 svg file
// @2 raster file
// @3 effect: rotate;...
QString svgfile(vars.at(1).toString());
QString effectfile(vars.at(2).toString());
QString effect(vars.at(3).toString());
bool meanIsReallyMean(false);
// qDebug()<<"Vars"<<vars.count();
if(vars.count() > 5)
{
int tmpMIRM(vars.at(5).toInt());
// qDebug()<<"tmp"<<vars.at(5)<<tmpMIRM;
if( tmpMIRM > 0)
meanIsReallyMean = true;
}
bool eRotate(effect == QString("r") || effect == QString("R"));
bool eScale(effect == QString("s") || effect == QString("S"));
bool eScaleAndRotate(effect == QString("w") || effect == QString("W"));
bool eInvert(effect == QString("R") || effect == QString("S") || effect == QString("W"));
ColorComponent cc(NoColorComponent);
QString ccString(vars.at(4).toString());
if(ccString == QString("r") || ccString == QString("R"))
cc = Red;
else if(ccString == QString("g") || ccString == QString("G"))
cc = Green;
else if(ccString == QString("b") || ccString == QString("B"))
cc = Blue;
else if(ccString == QString("h") || ccString == QString("H"))
cc = Hue;
else if(ccString == QString("s") || ccString == QString("S"))
cc = Saturation;
else if(ccString == QString("l") || ccString == QString("L"))
cc = Lightness;
if(QFile::exists(svgfile) && QFile::exists(effectfile)
&& (eRotate || eScale || eScaleAndRotate)
&& cc != NoColorComponent)
{
if(!imgCache.contains(svgfile))
{
imgCache.insert(svgfile, QImage());
if(!imgWatcher.files().contains(svgfile))
imgWatcher.addPath(svgfile);
}
QImage img;
if(imgCache.contains(effectfile))
img = imgCache.value(effectfile);
else
{
img.load(effectfile);
if(!img.isNull())
{
imgCache.insert(effectfile, img);
if(!imgWatcher.files().contains(effectfile))
imgWatcher.addPath(effectfile);
}
}
QSvgRenderer svgRdr(svgfile);
QRectF r(svgRdr.viewBoxF());
int cols(qRound(img.width() / r.width()));
int rows(qRound(img.height() / r.height()));
if(cols == 0 || rows == 0)
return;
// qDebug()<< "E"<<cols<<rows;
for(int y(0); y < rows; ++y)
{
for(int x(0); x < cols; ++x)
{
// qDebug()<<"I"<<x<<y;
int cxOrigin(x * r.width());
int cyOrigin(y * r.height());
int cRight(qMin(qRound(r.width()) + cxOrigin, img.width()));
int cBottom(qMin(qRound(r.height()) + cyOrigin, img.height()));
double val(0);
double nVal(0);
double cMean(0);
if(meanIsReallyMean)
{
for(int cy(cyOrigin); cy < cBottom; ++cy)
{
for(int cx(cxOrigin); cx < cRight; ++cx)
{
QColor ccolor(img.pixel(cx,cy));
if(cc == Red)
val += ccolor.redF();
else if(cc == Green)
val += ccolor.greenF();
else if(cc == Blue)
val += ccolor.blueF();
else if(cc == Hue)
val += ccolor.hslHueF();
else if(cc == Saturation)
val += ccolor.hslSaturationF();
else if(cc == Lightness)
val += ccolor.lightnessF();
++nVal;
}
}
cMean = val / nVal;
// qDebug()<<val<<cMean<<nVal;
}
else
{
QColor ccolor(img.pixel(cxOrigin + (r.width()/2),cyOrigin + (r.height()/2)));
if(cc == Red)
cMean = ccolor.redF();
else if(cc == Green)
cMean = ccolor.greenF();
else if(cc == Blue)
cMean = ccolor.blueF();
else if(cc == Hue)
cMean = ccolor.hslHueF();
else if(cc == Saturation)
cMean = ccolor.hslSaturationF();
else if(cc == Lightness)
cMean = ccolor.lightnessF();
}
if(eInvert)
cMean = 1 - cMean;
if(cMean == 0)
continue;
double tx((x * r.width()) + curPos.x());
double ty(y * r.height() + curPos.y());
double hW(r.width() / 2.0);
double hH(r.height() / 2.0);
painter->save();
painter->translate(tx, ty);
if(eRotate)
{
double rotVal(cMean * 360.0);
painter->setTransform(QTransform().translate(hW, hH).rotate(rotVal).translate(-hW, -hH), true);
}
else if(eScale)
{
// painter->scale(cMean, cMean);
painter->setTransform(QTransform().translate(hW, hH).scale(cMean, cMean).translate(-hW, -hH), true);
}
else if(eScaleAndRotate)
{
double rotVal(cMean * 360.0);
QTransform srTrans(QTransform().translate(hW, hH).scale(cMean, cMean).rotate(rotVal).translate(-hW, -hH));
// qDebug()<<srTrans;
painter->setTransform(srTrans, true);
}
svgRdr.render(painter, r);
painter->restore();
}
}
}
}
else if(command == QString("svg-effect2"))
{
// @1 svg file
// @2 raster file for rotate effect
// @3 rotate color component
// @4 raster file for scale effect
// @5 scale color component
// @6 inverse flag
QString svgfile(vars.at(1).toString());
QString effectfileRotate(vars.at(2).toString());
QString ccOptionRotate(vars.at(3).toString());
QString effectfileScale(vars.at(4).toString());
QString ccOptionScale(vars.at(5).toString());
bool eInvert(false);
if (vars.count() > 6) {
double invertOption(number(vars.at(6)));
eInvert = invertOption > 0.0;
}
ColorComponent ccRotate(NoColorComponent);
ColorComponent ccScale(NoColorComponent);
if(ccOptionRotate == QString("r") || ccOptionRotate == QString("R"))
ccRotate = Red;
else if(ccOptionRotate == QString("g") || ccOptionRotate == QString("G"))
ccRotate = Green;
else if(ccOptionRotate == QString("b") || ccOptionRotate == QString("B"))
ccRotate = Blue;
else if(ccOptionRotate == QString("h") || ccOptionRotate == QString("H"))
ccRotate = Hue;
else if(ccOptionRotate == QString("s") || ccOptionRotate == QString("S"))
ccRotate = Saturation;
else if(ccOptionRotate == QString("l") || ccOptionRotate == QString("L"))
ccRotate = Lightness;
if(ccOptionScale == QString("r") || ccOptionScale == QString("R"))
ccScale = Red;
else if(ccOptionScale == QString("g") || ccOptionScale == QString("G"))
ccScale = Green;
else if(ccOptionScale == QString("b") || ccOptionScale == QString("B"))
ccScale = Blue;
else if(ccOptionScale == QString("h") || ccOptionScale == QString("H"))
ccScale = Hue;
else if(ccOptionScale == QString("s") || ccOptionScale == QString("S"))
ccScale = Saturation;
else if(ccOptionScale == QString("l") || ccOptionScale == QString("L"))
ccScale = Lightness;
if(QFile::exists(svgfile)
&& QFile::exists(effectfileRotate)
&& QFile::exists(effectfileScale)
&& ccRotate != NoColorComponent
&& ccScale != NoColorComponent)
{
if(!imgCache.contains(svgfile))
{
imgCache.insert(svgfile, QImage());
if(!imgWatcher.files().contains(svgfile))
imgWatcher.addPath(svgfile);
}
QImage imgRotate, imgScale;
if(imgCache.contains(effectfileRotate))
imgRotate = imgCache.value(effectfileRotate);
else
{
imgRotate.load(effectfileRotate);
if(!imgRotate.isNull())
{
imgCache.insert(effectfileRotate, imgRotate);
if(!imgWatcher.files().contains(effectfileRotate))
imgWatcher.addPath(effectfileRotate);
}
}
if(imgCache.contains(effectfileScale))
imgScale = imgCache.value(effectfileScale);
else
{
imgScale.load(effectfileScale);
if(!imgScale.isNull())
{
imgCache.insert(effectfileScale, imgScale);
if(!imgWatcher.files().contains(effectfileScale))
imgWatcher.addPath(effectfileScale);
}
}
if ((imgScale.width() != imgRotate.width())
|| (imgScale.height() != imgRotate.height())) {
imgScale = imgScale.scaled(imgRotate.width(), imgRotate.height());
}
QSvgRenderer svgRdr(svgfile);
QRectF r(svgRdr.viewBoxF());
int cols(qRound(imgRotate.width() / r.width()));
int rows(qRound(imgRotate.height() / r.height()));
if(cols == 0 || rows == 0)
return;
for(int y(0); y < rows; ++y)
{
for(int x(0); x < cols; ++x)
{
// qDebug()<<"I"<<x<<y;
int cxOrigin(x * r.width());
int cyOrigin(y * r.height());
int cRight(qMin(qRound(r.width()) + cxOrigin, imgRotate.width()));
int cBottom(qMin(qRound(r.height()) + cyOrigin, imgRotate.height()));
double valRotate(0);
double nValRotate(0);
double cMeanRotate(0);
double valScale(0);
double nValScale(0);
double cMeanScale(0);
{
for(int cy(cyOrigin); cy < cBottom; ++cy)
{
for(int cx(cxOrigin); cx < cRight; ++cx)
{
QColor ccolorScale(imgScale.pixel(cx,cy));
if(ccScale == Red)
valScale += ccolorScale.redF();
else if(ccScale == Green)
valScale += ccolorScale.greenF();
else if(ccScale == Blue)
valScale += ccolorScale.blueF();
else if(ccScale == Hue)
valScale += ccolorScale.hslHueF();
else if(ccScale == Saturation)
valScale += ccolorScale.hslSaturationF();
else if(ccScale == Lightness)
valScale += ccolorScale.lightnessF();
++nValScale;
}
for(int cx(cxOrigin); cx < cRight; ++cx)
{
QColor ccolorRotate(imgRotate.pixel(cx,cy));
if(ccRotate == Red)
valRotate += ccolorRotate.redF();
else if(ccRotate == Green)
valRotate += ccolorRotate.greenF();
else if(ccRotate == Blue)
valRotate += ccolorRotate.blueF();
else if(ccRotate == Hue)
valRotate += ccolorRotate.hslHueF();
else if(ccRotate == Saturation)
valRotate += ccolorRotate.hslSaturationF();
else if(ccRotate == Lightness)
valRotate += ccolorRotate.lightnessF();
++nValRotate;
}
}
cMeanRotate = valRotate / nValRotate;
cMeanScale = valScale / nValScale;
}
if(eInvert) {
cMeanScale = 1 - cMeanScale;
cMeanRotate = 1 - cMeanRotate;
}
double tx((x * r.width()) + curPos.x());
double ty(y * r.height() + curPos.y());
double hW(r.width() / 2.0);
double hH(r.height() / 2.0);
painter->save();
painter->translate(tx, ty);
double rotVal(cMeanRotate * 360.0);
QTransform srTrans(QTransform().translate(hW, hH).scale(cMeanScale, cMeanScale).rotate(rotVal).translate(-hW, -hH));
painter->setTransform(srTrans, true);
svgRdr.render(painter, r);
painter->restore();
}
}
}
}
else if(command == QString("save"))
{
painter->save();
}
else if(command == QString("restore"))
{
painter->restore();
}
}
void Command::endDraw()
{
if(painter)
painter->drawPath(painterPath);
}
void Command::updateImgCache(const QString &fn)
{
qDebug()<<"updateImgCache"<<fn;
imgCache.remove(fn);
// imgWatcher.removePath(fn);
emit imageChanged();
}