diff --git a/stuff/profiles/layouts/rooms/Default/menubar_template.xml b/stuff/profiles/layouts/rooms/Default/menubar_template.xml index b671f81..09043ae 100644 --- a/stuff/profiles/layouts/rooms/Default/menubar_template.xml +++ b/stuff/profiles/layouts/rooms/Default/menubar_template.xml @@ -29,6 +29,7 @@ MI_SoundTrack MI_ExportXDTS MI_StopMotionExportImageSequence + MI_ExportTvpJson MI_PrintXsheet diff --git a/toonz/sources/toonz/CMakeLists.txt b/toonz/sources/toonz/CMakeLists.txt index fd87193..6332e91 100644 --- a/toonz/sources/toonz/CMakeLists.txt +++ b/toonz/sources/toonz/CMakeLists.txt @@ -193,6 +193,7 @@ set(HEADERS metnum.h processor.h predict3d.h + tvpjson_io.h ) set(SOURCES @@ -361,6 +362,7 @@ set(SOURCES xdtsimportpopup.cpp expressionreferencemanager.cpp tooloptionsshortcutinvoker.cpp + tvpjson_io.cpp # Tracker file dummyprocessor.cpp metnum.cpp diff --git a/toonz/sources/toonz/icons/dark/mimetypes/60/json_icon.svg b/toonz/sources/toonz/icons/dark/mimetypes/60/json_icon.svg new file mode 100644 index 0000000..e9d83f3 --- /dev/null +++ b/toonz/sources/toonz/icons/dark/mimetypes/60/json_icon.svg @@ -0,0 +1,110 @@ + +image/svg+xml + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/toonz/sources/toonz/mainwindow.cpp b/toonz/sources/toonz/mainwindow.cpp index 00e4e1d..7db34e3 100644 --- a/toonz/sources/toonz/mainwindow.cpp +++ b/toonz/sources/toonz/mainwindow.cpp @@ -1671,6 +1671,9 @@ void MainWindow::defineActions() { QT_TRANSLATE_NOOP("MainWindow", "Export Exchange Digital Time Sheet (XDTS)"), ""); + createMenuFileAction( + MI_ExportTvpJson, + QT_TRANSLATE_NOOP("MainWindow", "Export TVPaint JSON File"), ""); createMenuFileAction("MI_RunScript", QT_TR_NOOP("Run Script..."), "", "run_script"); createMenuFileAction("MI_OpenScriptConsole", diff --git a/toonz/sources/toonz/menubar.cpp b/toonz/sources/toonz/menubar.cpp index ab47897..33fe8e6 100644 --- a/toonz/sources/toonz/menubar.cpp +++ b/toonz/sources/toonz/menubar.cpp @@ -1108,6 +1108,7 @@ QMenuBar *StackedMenuBar::createFullMenuBar() { #if defined(x64) addMenuItem(exportMenu, MI_StopMotionExportImageSequence); #endif + addMenuItem(exportMenu, MI_ExportTvpJson); } fileMenu->addSeparator(); addMenuItem(fileMenu, MI_PrintXsheet); diff --git a/toonz/sources/toonz/menubarcommandids.h b/toonz/sources/toonz/menubarcommandids.h index 05ed07c..eb0f404 100644 --- a/toonz/sources/toonz/menubarcommandids.h +++ b/toonz/sources/toonz/menubarcommandids.h @@ -453,4 +453,5 @@ #define MI_FlipPrevGuideStroke "MI_FlipPrevGuideStroke" #define MI_ExportXDTS "MI_ExportXDTS" +#define MI_ExportTvpJson "MI_ExportTvpJson" #endif diff --git a/toonz/sources/toonz/toonz.qrc b/toonz/sources/toonz/toonz.qrc index 492add9..69514d3 100644 --- a/toonz/sources/toonz/toonz.qrc +++ b/toonz/sources/toonz/toonz.qrc @@ -166,7 +166,8 @@ icons/dark/mimetypes/60/svg_icon.svg icons/dark/mimetypes/60/audio_icon.svg icons/dark/mimetypes/60/script_icon.svg - icons/dark/mimetypes/60/broken_icon.svg + icons/dark/mimetypes/60/broken_icon.svg + icons/dark/mimetypes/60/json_icon.svg icons/dark/actions/16/render.svg diff --git a/toonz/sources/toonz/tvpjson_io.cpp b/toonz/sources/toonz/tvpjson_io.cpp new file mode 100644 index 0000000..4aaa470 --- /dev/null +++ b/toonz/sources/toonz/tvpjson_io.cpp @@ -0,0 +1,516 @@ +#include "tvpjson_io.h" + +#include "tsystem.h" +#include "toonz/toonzscene.h" +#include "toonz/tproject.h" +#include "toonz/levelset.h" +#include "toonz/txsheet.h" +#include "toonz/txshcell.h" +#include "toonz/txshsimplelevel.h" +#include "toonz/txshchildlevel.h" +#include "toonz/txsheethandle.h" +#include "toonz/tscenehandle.h" +#include "toonz/preferences.h" +#include "toonz/sceneproperties.h" +#include "toonz/tstageobject.h" +#include "toutputproperties.h" +#include "toonz/tstageobjecttree.h" +#include "toonz/tcamera.h" + +#include "toonzqt/menubarcommand.h" +#include "toonzqt/gutil.h" + +#include "tapp.h" +#include "menubarcommandids.h" +#include "filebrowserpopup.h" + +#include +#include +#include +#include +#include + +using namespace TvpJsonIo; + +namespace { + +QMap BlendingMatch = {{"Color", BlendMode_Color}, + {"Darken", BlendMode_Darken}}; + +QString getFrameNumberWithLetters(int frame) { + int letterNum = frame % 10; + QChar letter; + + switch (letterNum) { + case 0: + letter = QChar(); + break; + case 1: + letter = 'A'; + break; + case 2: + letter = 'B'; + break; + case 3: + letter = 'C'; + break; + case 4: + letter = 'D'; + break; + case 5: + letter = 'E'; + break; + case 6: + letter = 'F'; + break; + case 7: + letter = 'G'; + break; + case 8: + letter = 'H'; + break; + case 9: + letter = 'I'; + break; + default: + letter = QChar(); + break; + } + + QString number; + if (frame >= 10) { + number = QString::number(frame); + number.chop(1); + } else + number = "0"; + + return (QChar(letter).isNull()) ? number : number.append(letter); +} +} // namespace + +//----------------------------------------------------------------------------- +void TvpJsonLayerLinkItem::read(const QJsonObject& json) { + m_instance_index = json["instance-index"].toInt(); + m_instance_name = json["instance-name"].toString(); + m_file = json["file"].toString(); + QJsonArray imagesArray = json["images"].toArray(); + for (int imageIndex = 0; imageIndex < imagesArray.size(); imageIndex++) { + m_images.append(imagesArray[imageIndex].toInt()); + } +} + +void TvpJsonLayerLinkItem::write(QJsonObject& json) const { + json["instance-index"] = m_instance_index; + json["instance-name"] = m_instance_name; + json["file"] = m_file; + QJsonArray imagesArray; + for (const auto frame : m_images) { + imagesArray.append(frame); + } + json["images"] = imagesArray; +} + +void TvpJsonLayerLinkItem::build(int instance_index, QString instance_name, + QString file, QList images) { + m_instance_index = instance_index; + m_instance_name = instance_name; + m_file = file; + m_images = images; +} + +//----------------------------------------------------------------------------- +void TvpJsonLayer::read(const QJsonObject& json) { + m_name = json["name"].toString(); + m_visible = json["visible"].toBool(); + m_position = json["position"].toInt(); + m_opacity = json["opacity"].toInt(); + m_start = json["start"].toInt(); + m_end = json["end"].toInt(); + + QString blendModeName = json["blending-mode"].toString("Color"); + m_blending_mode = BlendingMatch.value(blendModeName, BlendMode_Color); + + QJsonArray linkArray = json["link"].toArray(); + for (int linkIndex = 0; linkIndex < linkArray.size(); linkIndex++) { + QJsonObject linkItemObject = linkArray[linkIndex].toObject(); + TvpJsonLayerLinkItem linkItem; + linkItem.read(linkItemObject); + m_link.append(linkItem); + } +} + +void TvpJsonLayer::write(QJsonObject& json) const { + json["name"] = m_name; + json["visible"] = m_visible; + json["position"] = m_position; + json["opacity"] = m_opacity; + json["start"] = m_start; + json["end"] = m_end; + + QString blendModeName = BlendingMatch.key(m_blending_mode, "Color"); + json["blending-mode"] = blendModeName; + + QJsonArray linkArray; + for (const auto linkItem : m_link) { + QJsonObject linkItemObject; + linkItem.write(linkItemObject); + linkArray.append(linkItemObject); + } + json["link"] = linkArray; +} + +void TvpJsonLayer::build(int index, ToonzScene* scene, TXshCellColumn* column) { + m_position = index; + column->getRange(m_start, m_end); + + TXshCell prevCell; + + TFilePath sceneFolder = + scene->decodeFilePath(scene->getScenePath().getParentDir()); + + // JSON�ɋL���”\���ǂ����`�F�b�N�ς݂̃��x�� + QMap checkedLevels; + // register the firstly-found level + TXshLevel* firstFoundLevel = nullptr; + + QList cellList; + QList> imgsList; + QMap> frameFormats; + + for (int row = m_start; row <= m_end; row++) { + TXshCell cell = column->getCell(row); + // continue if the cell is continuous + if (prevCell == cell) continue; + + // try to register the level. + TXshLevel* level = cell.getSimpleLevel(); + if (!level) + cell = TXshCell(); + else if (checkedLevels.contains(level)) { + if (checkedLevels[level].isEmpty()) + cell = TXshCell(); + else { + } // do nothing + } else // newly found level + { + // Only raster levels are exported + // currently, only the files located under the scene folder will be + // exported + if (level->getType() != OVL_XSHLEVEL) + cell = TXshCell(); + else { + TFilePath levelFullPath = scene->decodeFilePath(level->getPath()); + if (sceneFolder.isAncestorOf(levelFullPath)) { + checkedLevels[level] = levelFullPath - sceneFolder; + if (!firstFoundLevel) firstFoundLevel = level; + std::vector fids; + level->getFids(fids); + frameFormats[level] = QPair(fids[0].getZeroPadding(), + fids[0].getStartSeqInd()); + } else + cell = TXshCell(); + } + if (cell.isEmpty()) checkedLevels[level] = TFilePath(); + } + + // continue if the cell is continuous + if (prevCell == cell) continue; + + if (!cellList.contains(cell)) { + cellList.append(cell); + imgsList.append(QList()); + } + imgsList[cellList.indexOf(cell)].append(row); + + prevCell = cell; + } + + if (imgsList.isEmpty()) return; + + //------- + + for (int i = 0; i < imgsList.size(); ++i) { + TXshCell cell = cellList[i]; + + int instance_index = imgsList[i].at(0); + + QString instance_name; + QString file; + if (cell.isEmpty()) { // ��R�}�̏ꍇ + instance_name = QString::number(0); + TFrameId zeroFid(0, 0, frameFormats[firstFoundLevel].first, + frameFormats[firstFoundLevel].second); + TFilePath imgPath = checkedLevels[firstFoundLevel].withFrame(zeroFid); + file = imgPath.getQString(); + } else { + TFrameId fid = cell.getFrameId(); + + // convert the last one digit of the frame number to alphabet + // Ex. 12 -> 1B 21 -> 2A 30 -> 3 + if (Preferences::instance()->isShowFrameNumberWithLettersEnabled()) + instance_name = getFrameNumberWithLetters(fid.getNumber()); + else { + std::string frameNumber(""); + // set number + if (fid.getNumber() >= 0) frameNumber = std::to_string(fid.getNumber()); + // add letter + if (fid.getLetter() != 0) frameNumber.append(1, fid.getLetter()); + instance_name = QString::fromStdString(frameNumber); + } + + fid.setZeroPadding(frameFormats[cell.m_level.getPointer()].first); + fid.setStartSeqInd(frameFormats[cell.m_level.getPointer()].second); + TFilePath imgPath = + checkedLevels[cell.m_level.getPointer()].withFrame(fid); + file = imgPath.getQString(); + } + + TvpJsonLayerLinkItem linkItem; + linkItem.build(instance_index, instance_name, file, imgsList[i]); + m_link.append(linkItem); + } + + if (firstFoundLevel) + m_name = QString::fromStdWString(firstFoundLevel->getName()); + else + m_name = QString(); + + m_visible = column->isPreviewVisible(); + m_opacity = (int)column->getOpacity(); +} + +//----------------------------------------------------------------------------- +void TvpJsonClip::read(const QJsonObject& json) { + m_name = json["name"].toString("Untitled"); + m_cameraSize.setWidth(json["width"].toInt(1920)); + m_cameraSize.setHeight(json["height"].toInt(1080)); + m_framerate = json["framerate"].toDouble(24.0); + m_pixelaspectratio = json["pixelaspectratio"].toDouble(1.0); + m_image_count = json["image-count"].toInt(); + + QJsonObject bgObject = json["bg"].toObject(); + m_bg.setRed(bgObject["red"].toInt(255)); + m_bg.setGreen(bgObject["green"].toInt(255)); + m_bg.setBlue(bgObject["blue"].toInt(255)); + m_bg.setAlpha(255); + + QJsonArray layersArray = json["layers"].toArray(); + for (int layerIndex = 0; layerIndex < layersArray.size(); layerIndex++) { + QJsonObject layerObject = layersArray[layerIndex].toObject(); + TvpJsonLayer layer; + layer.read(layerObject); + m_layers.append(layer); + } +} + +void TvpJsonClip::write(QJsonObject& json) const { + json["name"] = m_name; + json["width"] = m_cameraSize.width(); + json["height"] = m_cameraSize.height(); + json["framerate"] = m_framerate; + json["pixelaspectratio"] = m_pixelaspectratio; + json["image-count"] = m_image_count; + + QJsonObject bgObject; + bgObject["red"] = m_bg.red(); + bgObject["green"] = m_bg.green(); + bgObject["blue"] = m_bg.blue(); + json["bg"] = bgObject; + + QJsonArray layersArray; + for (const auto layer : m_layers) { + QJsonObject layerObject; + layer.write(layerObject); + layersArray.append(layerObject); + } + json["layers"] = layersArray; +} + +void TvpJsonClip::build(ToonzScene* scene, TXsheet* xsheet) { + TFilePath fp = scene->getScenePath(); + m_name = QString::fromStdString(fp.getName()); + + TStageObjectId cameraId = xsheet->getStageObjectTree()->getCurrentCameraId(); + TCamera* currentCamera = xsheet->getStageObject(cameraId)->getCamera(); + TDimension cameraRes = currentCamera->getRes(); + m_cameraSize = QSize(cameraRes.lx, cameraRes.ly); + + TOutputProperties* outputProperties = + scene->getProperties()->getOutputProperties(); + m_framerate = outputProperties->getFrameRate(); + + TPointD cameraDpi = currentCamera->getDpi(); + m_pixelaspectratio = cameraDpi.y / cameraDpi.x; + + // if the current xsheet is top xsheet in the scene and the output + // frame range is specified, set the "to" frame value as duration + // TOutputProperties* oprop = scene->getProperties()->getOutputProperties(); + int from, to, step; + if (scene->getTopXsheet() == xsheet && + outputProperties->getRange(from, to, step)) + m_image_count = to + 1; + else + m_image_count = xsheet->getFrameCount(); + + TPixel bgColor = scene->getProperties()->getBgColor(); + m_bg = QColor((int)bgColor.r, (int)bgColor.g, (int)bgColor.b); + + if (xsheet->getColumnCount() == 0) return; + for (int col = xsheet->getColumnCount() - 1; col >= 0; col--) { + if (xsheet->isColumnEmpty(col)) { + continue; + } + TXshCellColumn* column = xsheet->getColumn(col)->getCellColumn(); + if (!column) { + continue; + } + TvpJsonLayer layer; + layer.build(col, scene, column); + if (!layer.isEmpty()) m_layers.append(layer); + } +} + +//----------------------------------------------------------------------------- +void TvpJsonProject::read(const QJsonObject& json) { + if (json.contains("format")) { + QJsonObject formatObject = json["format"].toObject(); + if (formatObject.contains("extension")) + m_formatExtension = formatObject["extension"].toString(); + } + QJsonObject clipObject = json["clip"].toObject(); + m_clip.read(clipObject); +} + +void TvpJsonProject::write(QJsonObject& json) const { + QJsonObject formatObject; + formatObject["extension"] = m_formatExtension; + json["format"] = formatObject; + + QJsonObject clipObject; + m_clip.write(clipObject); + json["clip"] = clipObject; +} + +void TvpJsonProject::build(ToonzScene* scene, TXsheet* xsheet) { + TOutputProperties* outputProperties = + scene->getProperties()->getOutputProperties(); + m_formatExtension = + QString::fromStdString(outputProperties->getPath().getType()); + + m_clip.build(scene, xsheet); +} + +//----------------------------------------------------------------------------- +void TvpJsonVersion::read(const QJsonObject& json) { + m_major = json["major"].toInt(); + m_minor = json["minor"].toInt(); +} + +void TvpJsonVersion::write(QJsonObject& json) const { + json["major"] = m_major; + json["minor"] = m_minor; +} + +void TvpJsonVersion::setVersion(int major, int minor) { + m_major = major; + m_minor = minor; +} + +//----------------------------------------------------------------------------- +void TvpJsonData::read(const QJsonObject& json) { + QJsonObject versionObject = json["version"].toObject(); + m_version.read(versionObject); + + QJsonObject projectObject = json["project"].toObject(); + m_project.read(projectObject); +} + +void TvpJsonData::write(QJsonObject& json) const { + QJsonObject versionObject; + m_version.write(versionObject); + json["version"] = versionObject; + + QJsonObject projectObject; + m_project.write(projectObject); + json["project"] = projectObject; +} + +void TvpJsonData::build(ToonzScene* scene, TXsheet* xsheet) { + // currently this i/o is based on version 5.1 files + m_version.setVersion(5, 1); + m_project.build(scene, xsheet); +} + +//----------------------------------------------------------------------------- + +class ExportTvpJsonCommand final : public MenuItemHandler { +public: + ExportTvpJsonCommand() : MenuItemHandler(MI_ExportTvpJson) {} + void execute() override; +} exportTvpJsonCommand; + +void ExportTvpJsonCommand::execute() { + ToonzScene* scene = TApp::instance()->getCurrentScene()->getScene(); + if (scene->isUntitled()) { + DVGui::error( + QObject::tr("TVPaint JSON file cannot be exported from untitled scene. " + "Save the scene first.")); + return; + } + TXsheet* xsheet = TApp::instance()->getCurrentXsheet()->getXsheet(); + TFilePath fp = scene->getScenePath().withType("json"); + + TvpJsonData tvpJsonData; + tvpJsonData.build(scene, xsheet); + if (tvpJsonData.isEmpty()) { + DVGui::error( + QObject::tr("No columns can be exported. Please note the followings:\n " + "- The level files must be placed at the same or child " + "folder relative to the scene file.\n - Currently only the " + "columns containing raster levels can be exported.")); + return; + } + + static GenericSaveFilePopup* savePopup = 0; + if (!savePopup) { + savePopup = + new GenericSaveFilePopup(QObject::tr("Export TVPaint JSON File")); + savePopup->addFilterType("json"); + } + if (!scene->isUntitled()) + savePopup->setFolder(fp.getParentDir()); + else + savePopup->setFolder( + TProjectManager::instance()->getCurrentProject()->getScenesPath()); + savePopup->setFilename(fp.withoutParentDir()); + fp = savePopup->getPath(); + if (fp.isEmpty()) return; + + QFile saveFile(fp.getQString()); + + if (!saveFile.open(QIODevice::WriteOnly)) { + qWarning("Couldn't open save file."); + return; + } + + QJsonObject tvpJsonObject; + tvpJsonData.write(tvpJsonObject); + QJsonDocument saveDoc(tvpJsonObject); + QByteArray jsonByteArrayData = saveDoc.toJson(); + saveFile.write(jsonByteArrayData); + + QString str = QObject::tr("The file %1 has been exported successfully.") + .arg(QString::fromStdString(fp.getLevelName())); + + std::vector buttons = {QObject::tr("OK"), + QObject::tr("Open containing folder")}; + int ret = DVGui::MsgBox(DVGui::INFORMATION, str, buttons); + + if (ret == 2) { + TFilePath folderPath = fp.getParentDir(); + if (TSystem::isUNC(folderPath)) + QDesktopServices::openUrl(QUrl(folderPath.getQString())); + else + QDesktopServices::openUrl(QUrl::fromLocalFile(folderPath.getQString())); + } +} diff --git a/toonz/sources/toonz/tvpjson_io.h b/toonz/sources/toonz/tvpjson_io.h new file mode 100644 index 0000000..68bbb11 --- /dev/null +++ b/toonz/sources/toonz/tvpjson_io.h @@ -0,0 +1,182 @@ +#pragma once +#ifndef TVPJSON_IO_H +#define TVPJSON_IO_H + +#include "tfilepath.h" + +#include +#include +#include +#include +#include +#include + +#include + +class ToonzScene; +class TFilePath; +class TXsheet; +class TXshCellColumn; +class QJsonObject; + +namespace TvpJsonIo { + +// Currently only supports "Color" and "Darken" brend modes +enum BlendMode { + BlendMode_Color, + // BlendMode_Behind, + // BlendMode_Erase, + // BlendMode_Shade, + // BlendMode_Light, + // BlendMode_Colorize, + // BlendMode_Hue, + // BlendMode_Saturation, + // BlendMode_Value, + // BlendMode_Add, + // BlendMode_Sub, + // BlendMode_Multiply, + // BlendMode_Screen, + // BlendMode_Replace, + // BlendMode_Copy, + // BlendMode_Difference, + // BlendMode_Divide, + // BlendMode_Overlay, + // BlendMode_Overlay2, + // BlendMode_Light2, + // BlendMode_Shade2, + // BlendMode_HardLight, + // BlendMode_SoftLight, + // BlendMode_GrainExtract, + // BlendMode_GrainMerge, + // BlendMode_Sub2, + BlendMode_Darken, + // BlendMode_Lighten, + BlendModeCount +}; + +// "description": "information of each cell and instance", +class TvpJsonLayerLinkItem { + // instance-index "description": "first placed frame of instance (the first + // frame is 0)" + int m_instance_index; + // instance-name "description": "drawing number (starting from 1. 0 is used + // for empty frame)" + QString m_instance_name; + // "description": "instance file path, relative to the scene file" + QString m_file; + // "description": "each start frame of the image (the first frame is 0)" + QList m_images; + +public: + void read(const QJsonObject& json); + void write(QJsonObject& json) const; + void build(int instance_index, QString instance_name, QString file, + QList images); +}; + +class TvpJsonLayer { + // "description": "layer name (= level name)" + QString m_name; + // "description": "visibility" + bool m_visible; + // "description": "layer index (stacking order), starting from 0" + int m_position; + // "description": "layer opacity 0-255" + int m_opacity; + // "description": "start frame of the layer" + int m_start; + // "description": "end frame of the layer" + int m_end; + + // pre_behavior, post_behavior : Unknown. Put 0 for now. + + // "description": "composite mode of the layers. "Color"��Normal, + // "Darken"��Darken" + BlendMode m_blending_mode; + + // group/red,green,blue "description": "Unknown. Put 0 for now" + // QColor m_group + + // "description": "information of each cell and instance", + QList m_link; + +public: + void read(const QJsonObject& json); + void write(QJsonObject& json) const; + void build(int index, ToonzScene*, TXshCellColumn* column); + bool isEmpty() { return m_link.isEmpty(); } +}; + +class TvpJsonClip { + // "description": "scene name" + QString m_name; + // "width": "description": "camera width in pixels" + // "height": "description": "camera height in pixels" + QSize m_cameraSize; + // "description": "frame rate" + double m_framerate; + // "description": "pixel aspect ratio" + double m_pixelaspectratio; + // "image-count": "description": "scene frame length" + int m_image_count; + // bg/red,green,blue "description": "camera BG color�i0-255 for each + // channel�j" + QColor m_bg; + + // camera : camera information. Ignore it for now. + + // markin, markout : Ignore for now. + + //"description": "layer information" + QList m_layers; + + // repeat : Ignore for now. + +public: + void read(const QJsonObject& json); + void write(QJsonObject& json) const; + bool isEmpty() { return m_layers.isEmpty(); } + void build(ToonzScene*, TXsheet*); +}; + +class TvpJsonProject { + // format/extension "description": "Output format extension??" + QString m_formatExtension; + // "description": "scene information" + TvpJsonClip m_clip; + +public: + void read(const QJsonObject& json); + void write(QJsonObject& json) const; + void build(ToonzScene*, TXsheet*); + bool isEmpty() { return m_clip.isEmpty(); } +}; + +class TvpJsonVersion { + // "description": "major version" + int m_major; + // "description": "minor version" + int m_minor; + +public: + void read(const QJsonObject& json); + void write(QJsonObject& json) const; + void setVersion(int, int); +}; + +class TvpJsonData { + // "description": "version number of this tvp-json format", + TvpJsonVersion m_version; + // "description": "project information" + TvpJsonProject m_project; + +public: + void read(const QJsonObject& json); + void write(QJsonObject& json) const; + void build(ToonzScene*, TXsheet*); + bool isEmpty() { return m_project.isEmpty(); } +}; + +} // namespace TvpJsonIo + +#endif \ No newline at end of file diff --git a/toonz/sources/toonzqt/icongenerator.cpp b/toonz/sources/toonzqt/icongenerator.cpp index d7df450..d0c4c5e 100644 --- a/toonz/sources/toonzqt/icongenerator.cpp +++ b/toonz/sources/toonzqt/icongenerator.cpp @@ -118,7 +118,7 @@ bool getIcon(const std::string &iconName, QPixmap &pix, ras->getSize().lx > standardSize.lx && ras->getSize().ly > standardSize.ly) isHighDpi = true; - pix = rasterToQPixmap(ras, false, isHighDpi); + pix = rasterToQPixmap(ras, false, isHighDpi); return true; } @@ -187,7 +187,7 @@ void makeChessBackground(const TRaster32P &ras) { int yCol = (y & 4); - for (int x = 0; pix != lineEnd; ++x, ++pix) + for (int x = 0; pix != lineEnd; ++x, ++pix) if (pix->m != 255) *pix = overPix((x & 4) == yCol ? gray1 : gray2, *pix); } @@ -605,8 +605,8 @@ TRaster32P SplineIconRenderer::generateRaster( double scaleX = 1, scaleY = 1; if (sbbox.getLx() > 0.0) scaleX = (double)iconSize.lx / sbbox.getLx(); if (sbbox.getLy() > 0.0) scaleY = (double)iconSize.ly / sbbox.getLy(); - double scale = 0.8 * std::min(scaleX, scaleY); - TPointD centerStroke = 0.5 * (sbbox.getP00() + sbbox.getP11()); + double scale = 0.8 * std::min(scaleX, scaleY); + TPointD centerStroke = 0.5 * (sbbox.getP00() + sbbox.getP11()); TPointD centerPixmap(iconSize.lx * 0.5, iconSize.ly * 0.5); glPushMatrix(); tglMultMatrix(TScale(scale).place(centerStroke, centerPixmap)); @@ -976,10 +976,10 @@ TRaster32P IconGenerator::generateVectorFileIcon(const TFilePath &path, TLevelReaderP lr(path); TLevelP level = lr->loadInfo(); if (level->begin() == level->end()) return TRaster32P(); - TFrameId frameId = fid; + TFrameId frameId = fid; if (fid == TFrameId::NO_FRAME) frameId = level->begin()->first; - TImageP img = lr->getFrameReader(frameId)->load(); - TVectorImageP vi = img; + TImageP img = lr->getFrameReader(frameId)->load(); + TVectorImageP vi = img; if (!vi) return TRaster32P(); vi->setPalette(level->getPalette()); VectorImageIconRenderer vir("", iconSize, vi.getPointer(), @@ -1117,7 +1117,7 @@ TRaster32P IconGenerator::generateMeshFileIcon(const TFilePath &path, TLevelP level = lr->loadInfo(); if (level->begin() == level->end()) return TRaster32P(); - TFrameId frameId = fid; + TFrameId frameId = fid; if (fid == TFrameId::NO_FRAME) frameId = level->begin()->first; TMeshImageP mi = lr->getFrameReader(frameId)->load(); @@ -1241,6 +1241,12 @@ void FileIconRenderer::run() { QSize(iconSize.lx, iconSize.ly), Qt::KeepAspectRatio)); setIcon(rasterFromQPixmap(script)); return; + } else if (type == "json") { + QPixmap json(svgToPixmap(getIconThemePath("mimetypes/60/json_icon.svg"), + QSize(iconSize.lx, iconSize.ly), + Qt::KeepAspectRatio)); + setIcon(rasterFromQPixmap(json)); + return; } else {