qt/LedOK/wProgramManager/mconverter.cpp
2022-08-25 18:37:24 +08:00

570 lines
23 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "mconverter.h"
#include "cfg.h"
#include "globaldefine.h"
#include "tools.h"
#include "wProgramManager/eaclock.h"
#include "wProgramManager/eaudio.h"
#include "wProgramManager/edclock.h"
#include "wProgramManager/eenviron.h"
#include "wProgramManager/egif.h"
#include "wProgramManager/etext.h"
#include "wProgramManager/etimer.h"
#include "wProgramManager/evideo.h"
#include <QBuffer>
#include <QJsonArray>
#include <QProcess>
mConverter::mConverter(const QString &prog_name, const QString &zip_file, const QString &password, QObject *parent) : QThread(parent), prog_name(prog_name), zip_file(zip_file), password(password) {
}
void mConverter::run() {
auto srcDir = programsDir() + "/" + prog_name;
dstDir = srcDir + "_tmp";
//清空目录
emit sProgress(tr("Preparing ..."), 0);
QDir rootDir(programsDir());
rootDir.remove(prog_name + "_tmp.zip");
QDir dstQDir(dstDir);
if(! dstQDir.exists() || dstQDir.removeRecursively()) {
int iReTryCount = 0;
while(!rootDir.mkdir(prog_name + "_tmp")) {
QThread::msleep(250);
iReTryCount++;
if(iReTryCount > 4) break;
}
}
//扫描节目, 返回多个节目数组
emit sProgress(tr("Scan program ..."), 30);
QStringList pageNames = QDir(srcDir).entryList(QDir::Dirs | QDir::NoDotAndDotDot);
//查询 order 属性, 将最上层的放在转换后 layers 的最前面
//一个 page.json 对应节目任务中的一个 items 里的 program
QList<QJsonDocument> pageJsons;
foreach(QString pageName, pageNames) {
QFile jsonFile(srcDir+"/"+pageName+"/page.json");
if(jsonFile.open(QIODevice::ReadOnly)){
QJsonDocument pageJson = QJsonDocument::fromJson(jsonFile.readAll());
jsonFile.close();
pageJsons.append(pageJson);
}
}
//根据order排序
std::sort(pageJsons.begin(), pageJsons.end(), [](const QJsonDocument &a, const QJsonDocument &b) {
return a["order"].toInt() < b["order"].toInt();
});
QJsonArray items;
foreach(QJsonDocument pageJson, pageJsons) {
srcPageDir = srcDir + "/" + pageJson["name"].toString();
items.append(cvtPage(pageJson));
}
emit sProgress(tr("Create json ..."), 60);
QJsonObject json;
json["_type"] = "PlayXixunTask";
json["id"] = QUuid::createUuid().toString(QUuid::WithoutBraces);
json["preDownloadURL"] = "http://192.168.8.202:23412/file/download?id=";
json["notificationURL"] = "http://192.168.8.202:23412/test";
json["task"] = QJsonObject{
{"_id", QUuid::createUuid().toString(QUuid::WithoutBraces)},
{"name", prog_name},
{"cmdId", QUuid::createUuid().toString(QUuid::WithoutBraces)},
{"items", items}
};
QFile program(dstDir + "/program");
if(program.open(QFile::WriteOnly)) {
program.write(QJsonDocument(json).toJson());
program.close();
}
//如果是usb更新则生成压缩包网络发送则不需要
if(! zip_file.isEmpty()) {
QStringList args{"a", zip_file, dstDir+"/*"};
if(! password.isEmpty()) args << "-p"+password;
QProcess::execute("7z.exe", args);
}
}
//此处需要把幻灯片中的元素按层顺序排序再放入layers中每个元素对一个layer。ewindow中的多个顺序元素为一个层上的时间轴上的素材
QJsonObject mConverter::cvtPage(const QJsonDocument &pageJson) {
auto audios = pageJson["audios"].toArray();
QJsonArray sources;
int start = 0;
foreach(auto audio, audios) {
auto dur = audio["dur"].toInt();
if(dur==0) continue;
auto name = audio["name"].toString();
if(name.isEmpty()) continue;
QString file = audio["dir"].toString()+"/"+name;
QFileInfo srcInfo(file);
if(! srcInfo.isFile()) continue;
QString id = Tools::fileMd5(file);
if(id.isEmpty()) continue;
QFile::copy(file, dstDir+"/"+id);
QJsonObject source;
source.insert("_type", "Audio");
source["id"] = id;
source["md5"] = id;
source["name"] = name;
source["size"] = srcInfo.size();
source["fileExt"] = srcInfo.suffix().toLower();
source["timeSpan"] = dur;
source["playTime"] = start;
source["vol"] = audio["vol"].toInt();
source["enabled"] = true;
source["left"] = -1;
source["top"] = -1;
source["width"] = 1;
source["height"] = 1;
sources.append(source);
start += dur;
}
QJsonArray layers;
if(! sources.isEmpty()) layers.append(QJsonObject{{"repeat", true}, {"sources", sources}});
auto elements = pageJson["elements"].toArray();
foreach(auto ele, elements) {
QString type = ele["elementType"].toString();
auto geometry = ele["geometry"];
QJsonArray sources;
if(type=="Window") {
auto elements = ele["elements"].toArray();
auto left = geometry["x"];
auto top = geometry["y"];
auto width = geometry["w"];
auto height = geometry["h"];
QList<QJsonObject> eles;
foreach(auto value, elements) eles.append(value.toObject());
std::sort(eles.begin(), eles.end(), [](const QJsonObject &a, const QJsonObject &b) {
return a["geometry"]["order"].toInt() < b["geometry"]["order"].toInt();
});
int playTime = 0;
foreach(const auto ele, eles) {
QJsonObject source = cvtEle(ele["elementType"].toString(), ele);
if(source.isEmpty()) continue;
source["left"] = left;
source["top"] = top;
source["width"] = width;
source["height"] = height;
source["playTime"] = playTime;
playTime += source["timeSpan"].toInt();
sources.append(source);
}
} else {
QJsonObject source = cvtEle(type, ele.toObject());
if(! source.isEmpty()) {
source["left"] = geometry["x"];
source["top"] = geometry["y"];
source["width"] = geometry["w"];
source["height"] = geometry["h"];
source["playTime"] = 0;
sources.append(source);
}
}
if(! sources.isEmpty()) {
QJsonObject layer{{"repeat", false}, {"sources", sources}};
auto border = ele["border"].toString();
if(! border.isEmpty()) {
QString bdSrc = ":res/borders/"+border;
QString id = Tools::fileMd5(bdSrc);
QFile::copy(bdSrc, dstDir+"/"+id);
auto borderSize = ele["borderSize"];
if(borderSize.isUndefined() || borderSize.isNull()){
QImage img(bdSrc);
borderSize = QJsonArray{img.width(), img.height()};
}
layer.insert("border", QJsonObject{
{"img", id},
{"eff", ele["borderEff"]},
{"speed", ele["borderSpeed"]},
{"img_size", borderSize},
{"geometry", QJsonArray{geometry["x"], geometry["y"], geometry["w"], geometry["h"]}}
});
}
layers.append(layer);
}
}
QJsonArray schedules, plans = pageJson["plans"].toArray();
auto validDate = pageJson["validDate"];
bool isValid = validDate["isValid"].toBool();
if(plans.isEmpty()) {
if(isValid) {
QJsonObject schedule;
schedule["dateType"] = "Range";
schedule["startDate"] = validDate["start"];
schedule["endDate"] = validDate["end"];
schedule["timeType"] = "All";
schedule["filterType"] = "None";
schedule["monthFilter"] = QJsonArray();
schedule["weekFilter"] = QJsonArray();
schedules.append(schedule);
}
} else {
foreach(QJsonValue plan, plans) {
QJsonObject schedule;
if(isValid) {
schedule["dateType"] = "Range";
schedule["startDate"] = validDate["start"];
schedule["endDate"] = validDate["end"];
} else schedule["dateType"] = "All";
schedule["timeType"] = "Range";
schedule["startTime"] = plan["start"];
schedule["endTime"] = plan["end"];
auto weekly = plan["weekly"];
schedule["weekFilter"] = weekly;
schedule["filterType"] = weekly.toArray().isEmpty() ? "None" : "Week";
schedule["monthFilter"] = QJsonArray();
schedules.append(schedule);
}
}
return QJsonObject{
{"_id", QUuid::createUuid().toString(QUuid::WithoutBraces)},
{"priority", 0},
{"version", 0},
{"schedules", schedules},
{"_program", QJsonObject{
{"_id", QUuid::createUuid().toString(QUuid::WithoutBraces)},
{"totalSize", 0},
{"name", pageJson["name"].toString()},
{"width", pageJson["resolution"]["w"]},
{"height", pageJson["resolution"]["h"]},
{"_company", "alahover"},
{"_department", "alahover"},
{"_role", "alahover"},
{"_user", "alahover"},
{"__v", 0},
{"dateCreated", pageJson["last_edit"]},
{"layers", layers}
}},
{"repeatTimes", pageJson["repeat"]}
};
}
QJsonObject mConverter::cvtEle(const QString &type, const QJsonObject &ele) {
if(type=="Text") return convertText(ele);
else if(type=="Photo") return convertPhoto(ele);
else if(type=="Movie") return EVideo::genProg(ele, dstDir);
else if(type=="Gif") return convertGif(ele);
else if(type=="DClock") return convertDClock(ele);
else if(type=="AClock") return convertAClock(ele);
else if(type=="Temp") return EEnviron::genProg(ele, dstDir, srcPageDir);
else if(type=="Web") return convertWeb(ele);
else if(type=="Timer") return convertTimer(ele);
else if(type=="Audio") return EAudio::genProg(ele, dstDir);
return QJsonObject();
}
QJsonObject mConverter::convertText(const QJsonObject &json) {
EText::Data attr;
EText::setElement(json, attr);
QJsonObject oRes;
oRes["_type"] = "MultiPng";
oRes["name"] = "MultiPng";
oRes["id"] = res_id++;
//把["widget"]["files"]字段的数组转成[{"text0.png","move up"}]
auto widget = json["widget"];
QJsonArray srcFiles = widget["files"].toArray();
oRes["iPicCount"] = srcFiles.count();
QJsonArray arrayPics;
QString filePrefix = srcPageDir+"/"+widget["idDir"].toString()+"/";
for(int i=0; i<srcFiles.count(); i++) {
QString srcFile = filePrefix + srcFiles[i].toString();
QFile srcQFile(srcFile);
if(! srcQFile.exists()) continue;
QJsonObject arrayPic;
QString id = Tools::fileMd5(srcFile);
srcQFile.copy(dstDir+"/"+id);
arrayPic["id"] = id;
arrayPic["mime"] = "image/png";
switch(attr.playStyle) {
//转换成多行文本
case EText::Flip:
arrayPic["effect"]=attr.turning.effect;
oRes["timeSpan"] = attr.turning.playDuration;
if(attr.turning.effectDuration>=attr.turning.pageDuration) attr.turning.effectDuration=attr.turning.pageDuration/2;
arrayPic["effectSpeed"]=attr.turning.effectDuration;
arrayPic["picDuration"]=attr.turning.pageDuration;
break;
case EText::Scroll:
if(attr.rolling.rollingStyle==0) arrayPic["effect"] = "right to left";
else if(attr.rolling.rollingStyle==1) arrayPic["effect"] = "bottom to top";
else if(attr.rolling.rollingStyle==2) arrayPic["effect"] = "left to right";
else if(attr.rolling.rollingStyle==3) arrayPic["effect"] = "top to bottom";
oRes["timeSpan"] = attr.rolling.playDuration;
arrayPic["effectSpeed"] = attr.rolling.rollingSpeed;
arrayPic["picDuration"] = 0;
break;
case EText::Static:
arrayPic["effect"]="no";
oRes["timeSpan"] = attr.playDuration;
arrayPic["effectSpeed"]=0;
arrayPic["picDuration"]=attr.playDuration;
break;
//转换成plainText
default: break;
}
arrayPics.append(arrayPic);
}
oRes["arrayPics"] = arrayPics;
return oRes;
}
//转换图片
QJsonObject mConverter::convertPhoto(const QJsonObject &ele){
auto widget = ele["widget"];
auto name = widget["file"].toString();
QString srcFile = widget["path"].toString() + "/" + name;
QFileInfo srcInfo(srcFile);
if(! srcInfo.isFile()) return QJsonObject();
QImage img(srcFile);
auto geometry = ele["geometry"];
int width = geometry["w"].toInt();
int height = geometry["h"].toInt();
QJsonObject source;
if(img.width() > width*2 && img.height() > height*2) {
QBuffer buf;
img.scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation).save(&buf, "PNG");
QCryptographicHash cryptoHash(QCryptographicHash::Md5);
cryptoHash.addData(buf.data());
auto md5 = QString::fromLatin1(cryptoHash.result().toHex());
QFile file(dstDir+"/"+md5);
if(! file.open(QFile::WriteOnly)) return source;
file.write(buf.data());
file.close();
source["id"] = md5;
source["md5"] = md5;
source["size"] = buf.size();
source["name"] = srcInfo.baseName()+".png";
source["fileExt"] = "png";
source["mime"] = "image/png";
} else {
auto md5 = Tools::fileMd5(srcFile);
if(md5.isEmpty()) return source;
QFile::copy(srcFile, dstDir+"/"+md5);
source["id"] = md5;
source["md5"] = md5;
source["size"] = srcInfo.size();
source["name"] = name;
QString sufLower = srcInfo.suffix().toLower();
source["fileExt"] = sufLower;
source["mime"] = "image/"+(sufLower=="jpg" ? "jpeg" : sufLower);
}
source["_type"] = "Image";
auto play = ele["play"];
source["timeSpan"] = play["playDuration"];
source["enabled"] = true;
source["enabledBy"] = "";
source["oldFilePath"] = "";
static const int effSize = 13;
static const int effs[effSize] = {0,1,3,4,5,6,7,9,10,11,12,17,18};
int enterStyle = play["enterStyle"].toInt();
source["entryEffect"] = enterStyle < effSize ? effs[enterStyle] : 0;
source["exitEffect"] = 0;
source["entryEffectTimeSpan"] = play["enterDuration"];
source["exitEffectTimeSpan"] = 0;
return source;
}
//转换图片
QJsonObject mConverter::convertGif(const QJsonObject &json) {
auto widget = json["widget"];
auto path = widget["path"].toString();
auto name = widget["file"].toString();
QString srcFile = path + "/" + name;
QFileInfo srcInfo(srcFile);
if(! srcInfo.isFile()) return QJsonObject();
QString id = Tools::fileMd5(srcFile);
if(id.isEmpty()) return QJsonObject();
QFile::copy(srcFile, dstDir+"/"+id);
QJsonObject oRes;
oRes["_type"] = "Image";
oRes["id"] = id;
oRes["md5"] = id;
oRes["name"] = name;
oRes["size"] = srcInfo.size();
QString suffix = srcInfo.suffix().toLower();
oRes["fileExt"] = suffix;
oRes["mime"] = "image/gif";
auto play = json["play"];
oRes["timeSpan"] = play["playDuration"].toInt() * play["playTimes"].toInt();
oRes["enabled"] = true;
oRes["entryEffect"] = "None";
oRes["exitEffect"] = "None";
oRes["entryEffectTimeSpan"] = 0;
oRes["exitEffectTimeSpan"] = 0;
return oRes;
}
QJsonObject mConverter::convertDClock(const QJsonObject &json){
QJsonObject oRes;
oRes["_type"] = "DigitalClockNew";
oRes["name"] = "DigitalClockNew";
oRes["id"] = "";
oRes["timeSpan"] = json["play"]["duration"];
oRes["timezone"] = 8;
auto widget = json["widget"];
oRes["year"] = widget["year"];
oRes["month"] = widget["month"];
oRes["day"] = widget["day"];
oRes["hour"] = widget["hour"];
oRes["min"] = widget["min"];
oRes["sec"] = widget["sec"];
oRes["weekly"] = widget["weekly"];
oRes["fullYear"] = widget["fullYear"];
oRes["hour12"] = widget["12Hour"];
oRes["AmPm"] = widget["AmPm"];
oRes["dateStyle"] = widget["dateStyle"];
oRes["timeStyle"] = widget["timeStyle"];
oRes["multiline"] = widget["multiline"];
oRes["fontSize"] = widget["font"]["size"];
oRes["entryEffect"] = "None";
oRes["exitEffect"] = "None";
oRes["entryEffectTimeSpan"] = 0;
oRes["exitEffectTimeSpan"] = 0;
auto fontVal = widget["font"];
auto textColor = Tools::int2Color(fontVal["color"].toInt());
QFont font(fontVal["family"].toString(), fontVal["size"].toInt());
font.setBold(fontVal["bold"].toBool());
font.setItalic(fontVal["italics"].toBool());
font.setUnderline(fontVal["underline"].toBool());
font.setStyleStrategy(gTextAntialiasing ? QFont::PreferAntialias : QFont::NoAntialias);
QFontMetricsF metricF(font);
oRes["spaceWidth"] = metricF.horizontalAdvance(" ");
QFontMetrics metric(font);
QColor color(textColor);
QJsonArray imgs;
for(auto str : str0_9) Tools::saveImg2(dstDir, metric, font, color, imgs, str, str);
Tools::saveImg2(dstDir, metric, font, color, imgs, tr("MON"), "MON");
Tools::saveImg2(dstDir, metric, font, color, imgs, tr("TUE"), "TUE");
Tools::saveImg2(dstDir, metric, font, color, imgs, tr("WED"), "WED");
Tools::saveImg2(dstDir, metric, font, color, imgs, tr("THU"), "THU");
Tools::saveImg2(dstDir, metric, font, color, imgs, tr("FRI"), "FRI");
Tools::saveImg2(dstDir, metric, font, color, imgs, tr("SAT"), "SAT");
Tools::saveImg2(dstDir, metric, font, color, imgs, tr("SUN"), "SUN");
Tools::saveImg2(dstDir, metric, font, color, imgs, tr("AM"), "AM");
Tools::saveImg2(dstDir, metric, font, color, imgs, tr("PM"), "PM");
Tools::saveImg2(dstDir, metric, font, color, imgs, "", "YEAR");
Tools::saveImg2(dstDir, metric, font, color, imgs, "", "MONTH");
Tools::saveImg2(dstDir, metric, font, color, imgs, "", "DAY");
Tools::saveImg2(dstDir, metric, font, color, imgs, ":", "maohao");
Tools::saveImg2(dstDir, metric, font, color, imgs, "/", "xiegang");
Tools::saveImg2(dstDir, metric, font, color, imgs, "-", "hengxian");
oRes["iPicCount"] = imgs.size();
oRes["arrayPics"] = imgs;
return oRes;
}
QJsonObject mConverter::convertAClock(const QJsonObject &json) {
auto widget = json["widget"];
QString srcFile = srcPageDir + "/" + widget["selfCreateDialName"].toString();
QFile srcQFile(srcFile);
if(! srcQFile.exists()) return QJsonObject();
QString id = Tools::fileMd5(srcFile);
srcQFile.copy(dstDir+"/"+id);
QJsonObject oRes;
oRes["_type"] = "AnalogClock";
oRes["id"] = id;
oRes["md5"] = id;
oRes["mime"] = "image/png";
oRes["name"] = "001";
oRes["timeSpan"] = json["play"]["duration"];
oRes["shade"] = 0;//表盘形状
oRes["opacity"] = 1;//透明度
oRes["showBg"] = false;//是否显示背景色
oRes["bgColor"] = 0;
oRes["showHourScale"] = false;//是否显示时针
auto color = widget["hourMarkColor"];
oRes["scaleHourColor"] = color.isString() ? color : Tools::int2Color(color.toInt()).name();
color = widget["minMarkColor"];
oRes["scaleMinColor"] = color.isString() ? color : Tools::int2Color(color.toInt()).name();
color = widget["hourHandColor"];
oRes["pinHourColor"] = color.isString() ? color : Tools::int2Color(color.toInt()).name();
color = widget["minHandColor"];
oRes["pinMinColor"] = color.isString() ? color : Tools::int2Color(color.toInt()).name();
color = widget["secHandColor"];
oRes["pinSecColor"] = color.isString() ? color : Tools::int2Color(color.toInt()).name();
oRes["showMinScale"] = false;
oRes["scaleStyle"] = 0;
oRes["showScaleNum"] = false;
oRes["pinStyle"] = 1;
oRes["showSecond"] = true;
//下同Video
oRes["entryEffect"] = "None";
oRes["exitEffect"] = "None";
oRes["entryEffectTimeSpan"] = 0;
oRes["exitEffectTimeSpan"] = 0 ;
return oRes;
}
QJsonObject mConverter::convertWeb(const QJsonObject &res) {
QJsonObject dst;
dst["_type"] = "WebURL";
dst["id"] = "";
dst["name"] = "WebURL";
dst["url"] = res["url"];
dst["timeSpan"] = res["duration"];
return dst;
}
QJsonObject mConverter::convertTimer(const QJsonObject &json) {
QJsonObject oRes;
oRes["_type"] = "Timer";
oRes["name"] = "Timer";
oRes["id"] = "";
oRes["targetTime"] = json["targetTime"];
oRes["isDown"] = json["isDown"];
oRes["hasDay"] = json["hasDay"];
oRes["hasHour"] = json["hasHour"];
oRes["hasMin"] = json["hasMin"];
oRes["hasSec"] = json["hasSec"];
oRes["isMultiline"] = json["isMultiline"];
auto text = json["text"].toString();
oRes["text"] = text;
QFont font(json["font"].toString(), json["fontSize"].toInt());
font.setBold(json["fontBold"].toBool());
font.setItalic(json["fontItalic"].toBool());
font.setUnderline(json["fontUnderline"].toBool());
oRes["font"] = font.family();
oRes["fontSize"] = font.pointSize();
oRes["fontBold"] = font.bold();
oRes["fontItalic"] = font.italic();
oRes["fontUnderline"] = font.underline();
auto textColor = json["textColor"].toString();
oRes["textColor"] = textColor;
oRes["backColor"] = json["backColor"];
oRes["timeSpan"] = json["duration"];
font.setStyleStrategy(gTextAntialiasing ? QFont::PreferAntialias : QFont::NoAntialias);
QFontMetricsF metricF(font);
oRes["spaceWidth"] = metricF.horizontalAdvance(" ");
QFontMetrics metric(font);
QColor color(textColor);
QJsonObject imgs;
for(auto str : str0_9) Tools::saveImg(dstDir, metric, font, color, imgs, str, str);
Tools::saveImg(dstDir, metric, font, color, imgs, tr("day"), "day");
Tools::saveImg(dstDir, metric, font, color, imgs, tr("hour"), "hour");
Tools::saveImg(dstDir, metric, font, color, imgs, tr("min"), "min");
Tools::saveImg(dstDir, metric, font, color, imgs, tr("sec"), "sec");
auto innerW = json["innerW"].toInt();
auto innerH = json["innerH"].toInt();
auto rect = metric.boundingRect(0, 0, innerW, innerH, Qt::AlignCenter | Qt::TextWordWrap, text);
QImage img(qMin(rect.width(), innerW), qMin(rect.height(), innerH), QImage::Format_ARGB32);
img.fill(Qt::transparent);
QPainter painter(&img);
painter.setFont(font);
painter.setPen(color);
painter.drawText(QRectF(0, 0, img.width(), img.height()), text, QTextOption(Qt::AlignCenter));
QBuffer buf;
if(img.save(&buf, "PNG")) {
QCryptographicHash cryptoHash(QCryptographicHash::Md5);
cryptoHash.addData(buf.data());
auto md5 = QString::fromLatin1(cryptoHash.result().toHex());
QFile file(dstDir+"/"+md5);
if(file.open(QFile::WriteOnly)) {
file.write(buf.data());
file.close();
imgs.insert("text", md5);
}
}
oRes["imgs"] = imgs;
return oRes;
}