qt/LedOK/program/gentmpthread.cpp
2023-10-23 14:58:29 +08:00

656 lines
26 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 "gentmpthread.h"
#include "cfg.h"
#include "globaldefine.h"
#include "tools.h"
#include "program/eenviron.h"
#include "program/etext.h"
#include "program/evideo.h"
#include <QBuffer>
#include <QProcess>
#include <QMessageBox>
#include <QPainter>
GenTmpThread::GenTmpThread(ProgItem *progItem, const QString &prog_name, const QString &zip_file, const QString &password) : mProgItem(progItem), prog_name(prog_name), zip_file(zip_file), password(password) {
connect(this, &QThread::finished, this, &QThread::deleteLater);
}
void GenTmpThread::run() {
auto srcDir = programsDir() + "/" + prog_name;
dstDir = srcDir + "_tmp";
//清空目录
QDir progsDir(programsDir());
progsDir.remove(prog_name + "_tmp.zip");
QDir dstQDir(dstDir);
if(! dstQDir.exists() || dstQDir.removeRecursively()) {
int iReTryCount = 0;
while(!progsDir.mkdir(prog_name + "_tmp")) {
QThread::msleep(250);
iReTryCount++;
if(iReTryCount > 4) break;
}
}
QFile jsonFile(srcDir+"/pro.json");
if(! jsonFile.open(QIODevice::ReadOnly)) {
emit onErr("Can't open "+srcDir+"/pro.json");
return;
}
auto data = jsonFile.readAll();
jsonFile.close();
QString error;
auto proJson = JFrom(data, &error).toObj();
if(! error.isEmpty()) {
emit onErr("Parse "+srcDir+"/pro.json Error: "+error);
return;
}
//扫描节目, 返回多个节目数组
QStringList pageNames = QDir(srcDir).entryList(QDir::Dirs | QDir::NoDotAndDotDot);
//查询 order 属性, 将最上层的放在转换后 layers 的最前面
//一个 page.json 对应节目任务中的一个 items 里的 program
std::vector<JObj> pageJsons;
for(auto &pageName : pageNames) {
QFile jsonFile(srcDir+"/"+pageName+"/page.json");
if(jsonFile.open(QIODevice::ReadOnly)) {
auto data = jsonFile.readAll();
jsonFile.close();
auto pageJson = JFrom(data, &error).toObj();
if(error.isEmpty()) pageJsons.emplace_back(pageJson);
}
}
std::sort(pageJsons.begin(), pageJsons.end(), [](const JObj &a, const JObj &b) {
return a["order"].toInt() < b["order"].toInt();
});
JArray items;
for(auto pageJson : pageJsons) {
srcPageDir = srcDir + "/" + pageJson["name"].toString();
items.append(cvtPage(pageJson, proJson));
}
JObj 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"] = JObj{
{"_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(JToBytes(json, "\t"));
program.close();
}
//如果是usb更新则生成压缩包网络发送则不需要
if(! zip_file.isEmpty()) {
#ifdef Q_OS_WIN
QStringList args{"a", zip_file, dstDir+"/*"};
if(! password.isEmpty()) args << "-p"+password;
QProcess::execute("7z.exe", args);
#else
QStringList args{"-r", zip_file};
if(! password.isEmpty()) args << "-P" << password;
args += QDir(dstDir).entryList(QDir::AllEntries | QDir::NoDotAndDotDot);
QProcess process;
process.setWorkingDirectory(dstDir);
process.start("zip", args);
process.waitForFinished();
#endif
}
}
//此处需要把幻灯片中的元素按层顺序排序再放入layers中每个元素对一个layer。ewindow中的多个顺序元素为一个层上的时间轴上的素材
JObj GenTmpThread::cvtPage(const JObj &pageJson, const JObj &proJson) {
auto audios = pageJson("audios").toArray();
auto sourceRepeat = pageJson["loop"].toBool();
JArray sources;
int start = 0;
for(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);
JObj 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;
}
JArray layers;
if(! sources.empty()) layers.append(JObj{{"repeat", sourceRepeat}, {"sources", sources}});
auto elements = pageJson["elements"].toArray();
for(auto &ele : elements) {
auto type = ele["elementType"].toString();
auto geometry = ele["geometry"];
JArray 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<JObj> eles;
for(auto &value : elements) eles.append(value.toObj());
int playTime = 0;
for(const auto &ele : eles) {
auto source = cvtEle(ele["elementType"].toString(), ele);
if(source.empty()) continue;
source["left"] = left;
source["top"] = top;
source["width"] = width;
source["height"] = height;
source["playTime"] = playTime;
playTime += source["timeSpan"].toInt();
sources.append(source);
}
} else {
auto source = cvtEle(type, ele.toObj());
if(! source.empty()) {
if(mProgItem->mMaxWidth && (type=="Photo" || type=="Movie")) {
source["left"] = 0;
source["top"] = 0;
source["width"] = mProgItem->mMaxWidth;
source["height"] = mProgItem->mHeight * mProgItem->mSplitWidths.size();
} else {
source["left"] = geometry["x"];
source["top"] = geometry["y"];
source["width"] = geometry["w"];
source["height"] = geometry["h"];
}
source["playTime"] = 0;
sources.append(source);
}
}
if(! sources.empty()) {
JObj layer{{"repeat", sourceRepeat}, {"sources", sources}};
auto border = ele["border"].toString();
if(! border.isEmpty()) {
QString bdSrc = "borders/"+border;
QString id = Tools::fileMd5(bdSrc);
QFile::copy(bdSrc, dstDir+"/"+id);
auto borderSize = ele["borderSize"];
if(borderSize.isNull()){
QImage img(bdSrc);
borderSize = JArray{img.width(), img.height()};
}
layer["border"] = JObj{
{"img", id},
{"eff", ele["borderEff"]},
{"speed", ele["borderSpeed"]},
{"img_size", borderSize},
{"geometry", JArray{geometry["x"], geometry["y"], geometry["w"], geometry["h"]}}
};
}
layers.append(layer);
}
}
JArray schedules, plans = pageJson["plans"].toArray();
auto validDate = pageJson["validDate"];
bool isValid = validDate["isValid"].toBool();
if(plans.empty()) {
if(isValid) {
JObj schedule;
schedule["dateType"] = "Range";
schedule["startDate"] = validDate["start"];
schedule["endDate"] = validDate["end"];
schedule["timeType"] = "All";
schedule["filterType"] = "None";
schedule["monthFilter"] = JArray();
schedule["weekFilter"] = JArray();
schedules.append(schedule);
}
} else {
for(auto &plan : plans) {
JObj 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().empty() ? "None" : "Week";
schedule["monthFilter"] = JArray();
schedules.append(schedule);
}
}
return JObj{
{"_id", QUuid::createUuid().toString(QUuid::WithoutBraces)},
{"priority", 0},
{"version", 0},
{"schedules", schedules},
{"_program", JObj{
{"_id", QUuid::createUuid().toString(QUuid::WithoutBraces)},
{"totalSize", 0},
{"name", pageJson["name"].toString()},
{"width", proJson["resolution"]["w"]},
{"height", proJson["resolution"]["h"]},
{"splitWidths", proJson["splitWidths"]},
{"_company", "alahover"},
{"_department", "alahover"},
{"_role", "alahover"},
{"_user", "alahover"},
{"__v", 0},
{"dateCreated", pageJson["last_edit"]},
{"layers", layers}
}},
{"repeatTimes", pageJson["repeat"]}
};
}
JObj GenTmpThread::cvtEle(const QString &type, const JObj &ele) {
if(type=="Text") return convertText(ele);
else if(type=="Photo") return convertPhoto(ele);
else if(type=="Movie") return EVideo::genProg(ele, dstDir, mProgItem);
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);
return JObj();
}
JObj GenTmpThread::convertText(const JObj &json) {
EText::Data attr;
EText::setElement(json, attr);
JObj source;
auto type = mProgItem->mMaxWidth ? "SplitText" : "MultiPng";
source["_type"] = type;
source["name"] = type;
source["id"] = res_id++;
auto widget = json["widget"];
QTextEdit fdText;
auto ft = fdText.font();
ft.setFamilies({"Arial","黑体"});
ft.setPixelSize(16);
fdText.setFont(ft);
auto pal = fdText.palette();
pal.setColor(QPalette::Base, Qt::black);
pal.setColor(QPalette::Text, Qt::white);
fdText.setPalette(pal);
fdText.setHtml(widget["text"].toStr());
source["text"] = fdText.toPlainText();
auto cursor = fdText.textCursor();
cursor.movePosition(QTextCursor::End);
auto format = cursor.charFormat();
source["fontSize"] = format.font().pixelSize();
auto foreground = format.foreground();
source["textColor"] = (foreground.style()==Qt::NoBrush ? Qt::white : foreground.color()).name(QColor::HexArgb);
source["backColor"] = widget["backColor"];
JArray srcFiles = widget["files"].toArray();
source["iPicCount"] = (int)srcFiles.size();
if(attr.playMode==EText::Flip) {
source["playMode"] = "Flip";
source["timeSpan"] = attr.flip.pageDuration * (int)srcFiles.size();
if(attr.flip.effectDuration >= attr.flip.pageDuration) attr.flip.effectDuration = attr.flip.pageDuration / 2;
} else if(attr.playMode==EText::Scroll) {
source["playMode"] = "Scroll";
source["timeSpan"] = attr.scroll.duration;
} else if(attr.playMode==EText::Static) {
source["playMode"] = "Static";
source["timeSpan"] = attr.duration;
}
JArray arrayPics;
auto filePrefix = srcPageDir+"/"+widget["idDir"].toString()+"/";
for(int i=0; i<(int)srcFiles.size(); i++) {
auto srcFile = filePrefix + srcFiles[i].toString();
QFile srcQFile(srcFile);
if(! srcQFile.exists()) continue;
JObj arrayPic;
auto id = Tools::fileMd5(srcFile);
srcQFile.copy(dstDir+"/"+id);
arrayPic["id"] = id;
arrayPic["mime"] = "image/png";
if(attr.playMode==EText::Flip) {
arrayPic["effect"] = attr.flip.effect;
arrayPic["effectSpeed"] = attr.flip.effectDuration;
arrayPic["picDuration"] = attr.flip.pageDuration;
} else if(attr.playMode==EText::Scroll) {
if(attr.scroll.effect==0) arrayPic["effect"] = "right to left";
else if(attr.scroll.effect==1) arrayPic["effect"] = "bottom to top";
else if(attr.scroll.effect==2) arrayPic["effect"] = "left to right";
else if(attr.scroll.effect==3) arrayPic["effect"] = "top to bottom";
arrayPic["effectSpeed"] = attr.scroll.effectSpeed;
arrayPic["picDuration"] = 0;
} else if(attr.playMode==EText::Static) {
arrayPic["effect"] = "no";
arrayPic["effectSpeed"] = 0;
arrayPic["picDuration"] = attr.duration;
}
arrayPics.append(arrayPic);
}
source["arrayPics"] = arrayPics;
return source;
}
//转换图片
JObj GenTmpThread::convertPhoto(const JObj &ele){
auto widget = ele["widget"];
auto name = widget["file"].toString();
QString srcFile = widget["path"].toString() + "/" + name;
QFileInfo srcInfo(srcFile);
JObj source;
if(! srcInfo.isFile()) return source;
QImage img(srcFile);
auto geometry = ele["geometry"];
auto x = geometry["x"].toInt();
auto y = geometry["y"].toInt();
auto width = geometry["w"].toInt();
auto height = geometry["h"].toInt();
if(mProgItem->mMaxWidth) {
auto scaled = img.scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
QImage square(gProgItem->mMaxWidth, gProgItem->mHeight*gProgItem->mSplitWidths.size(), QImage::Format_ARGB32);
square.fill(0);
QPainter painter(&square);
QPointF pos(x, y);
painter.drawImage(pos, scaled, QRectF(0, 0, gProgItem->mSplitWidths[0]-pos.x(), height));
auto end = gProgItem->mSplitWidths.size();
for(int i=1; i<end; i++) {
pos.rx() -= gProgItem->mSplitWidths[i-1];
pos.ry() += gProgItem->mHeight;
painter.drawImage(pos, scaled, QRectF(0, 0, gProgItem->mSplitWidths[i]-pos.x(), height));
}
QBuffer buf;
square.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 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;
}
//转换图片
JObj GenTmpThread::convertGif(const JObj &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 JObj();
QString id = Tools::fileMd5(srcFile);
if(id.isEmpty()) return JObj();
QFile::copy(srcFile, dstDir+"/"+id);
JObj 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;
}
JObj GenTmpThread::convertDClock(const JObj &json){
JObj oRes;
oRes["_type"] = "DigitalClockNew";
oRes["name"] = "DigitalClockNew";
oRes["id"] = "";
oRes["timeSpan"] = json["play"]["duration"];
auto widget = json["widget"];
oRes["timeZone"] = widget["timeZone"];
oRes["timezone"] = 8;//兼容旧播放器
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());
font.setPixelSize(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);
JArray 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"] = (int)imgs.size();
oRes["arrayPics"] = imgs;
return oRes;
}
JObj GenTmpThread::convertAClock(const JObj &json) {
auto widget = json["widget"];
QString srcFile = srcPageDir + "/" + widget["selfCreateDialName"].toString();
QFile srcQFile(srcFile);
if(! srcQFile.exists()) return JObj();
QString id = Tools::fileMd5(srcFile);
srcQFile.copy(dstDir+"/"+id);
JObj 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.isStr() ? color : Tools::int2Color(color.toInt()).name();
color = widget["minMarkColor"];
oRes["scaleMinColor"] = color.isStr() ? color : Tools::int2Color(color.toInt()).name();
color = widget["hourHandColor"];
oRes["pinHourColor"] = color.isStr() ? color : Tools::int2Color(color.toInt()).name();
color = widget["minHandColor"];
oRes["pinMinColor"] = color.isStr() ? color : Tools::int2Color(color.toInt()).name();
color = widget["secHandColor"];
oRes["pinSecColor"] = color.isStr() ? color : Tools::int2Color(color.toInt()).name();
oRes["pinHourLen"] = widget["hhLen"].toInt();
oRes["pinMinLen"] = widget["mhLen"].toInt();
oRes["pinSecLen"] = widget["shLen"].toInt();
oRes["pinHourWidth"] = widget["hhWidth"].toInt();
oRes["pinMinWidth"] = widget["mhWidth"].toInt();
oRes["pinSecWidth"] = widget["shWidth"].toInt();
oRes["showMinScale"] = false;
oRes["scaleStyle"] = 0;
oRes["showScaleNum"] = false;
oRes["pinStyle"] = 1;
oRes["showSecond"] = widget["showSecHand"];
oRes["timeZone"] = widget["timeZone"];
//下同Video
oRes["entryEffect"] = "None";
oRes["exitEffect"] = "None";
oRes["entryEffectTimeSpan"] = 0;
oRes["exitEffectTimeSpan"] = 0 ;
return oRes;
}
JObj GenTmpThread::convertWeb(const JObj &res) {
JObj dst;
dst["_type"] = "WebURL";
dst["id"] = "";
dst["name"] = "WebURL";
dst["url"] = res["url"];
dst["timeSpan"] = res["duration"];
return dst;
}
JObj GenTmpThread::convertTimer(const JObj &json) {
JObj 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());
font.setPixelSize(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.pixelSize();
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);
JObj 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");
if(! text.isEmpty()) {
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));
}
QByteArray data;
QBuffer buffer(&data);
buffer.open(QIODevice::WriteOnly);
if(img.save(&buffer, "PNG")) {
QCryptographicHash cryptoHash(QCryptographicHash::Md5);
cryptoHash.addData(data);
auto md5 = QString::fromLatin1(cryptoHash.result().toHex());
QFile file(dstDir+"/"+md5);
if(file.open(QFile::WriteOnly)) {
file.write(data);
file.close();
imgs.insert("text", md5);
} else emit onErr("convertTimer file.open false");
} else emit onErr("convertTimer img.save false");
}
oRes["imgs"] = imgs;
return oRes;
}