From 1584bbb473a5d05d37593c9ce9426ff0b74f9025 Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: May 19 2017 09:01:43 +0000 Subject: Fixes on convert feature from NAA raster images to TLV (#1203) * prevent the gap on anti-aliased * add dpi settings --- diff --git a/toonz/sources/include/convert2tlv.h b/toonz/sources/include/convert2tlv.h index 5c850ea..0051ffe 100644 --- a/toonz/sources/include/convert2tlv.h +++ b/toonz/sources/include/convert2tlv.h @@ -39,6 +39,8 @@ private: bool m_isUnpaintedFromNAA; bool m_appendDefaultPalette; + double m_dpi; + void buildToonzRaster(TRasterCM32P &rout, const TRasterP &rin1, const TRasterP &rin2); void doFill(TRasterCM32P &rout, const TRaster32P &rin); @@ -66,7 +68,7 @@ public: const TFilePath &outFolder, const QString &outName, int from, int to, bool doAutoclose, const TFilePath &palettePath, int colorTolerance, int antialiasType, int antialiasValue, - bool isUnpaintedFromNAA, bool appendDefaultPalette); + bool isUnpaintedFromNAA, bool appendDefaultPalette, double dpi); bool init(std::string &errorMessage); int getFramesToConvertCount(); diff --git a/toonz/sources/include/toonz/Naa2TlvConverter.h b/toonz/sources/include/toonz/Naa2TlvConverter.h index 29627d3..4f2fd8f 100644 --- a/toonz/sources/include/toonz/Naa2TlvConverter.h +++ b/toonz/sources/include/toonz/Naa2TlvConverter.h @@ -146,7 +146,8 @@ public: return -1; } - TToonzImageP makeTlv(bool transparentSyntheticInks, QList &usedStyleIds); + TToonzImageP makeTlv(bool transparentSyntheticInks, QList &usedStyleIds, + double dpi = 0.0); TVectorImageP vectorize(const TToonzImageP &ti); TVectorImageP vectorize(const TRaster32P &ras); diff --git a/toonz/sources/include/toonzqt/imageutils.h b/toonz/sources/include/toonzqt/imageutils.h index 6c73ebe..dce4955 100644 --- a/toonz/sources/include/toonzqt/imageutils.h +++ b/toonz/sources/include/toonzqt/imageutils.h @@ -113,8 +113,8 @@ void DVAPI convertNaa2Tlv( TPalette *palette = 0, //!< Special conversion function from an antialiased level to tlv. //! \sa Function ImageUtils::convert(). - bool removeUnusedStyles = - false); //! Remove unused styles from input palette. + bool removeUnusedStyles = false, + double dpi = 0.0); //! Remove unused styles from input palette. double DVAPI getQuantizedZoomFactor(double zf, bool forward); diff --git a/toonz/sources/toonz/convertpopup.cpp b/toonz/sources/toonz/convertpopup.cpp index 1fa04a3..d53bdc9 100644 --- a/toonz/sources/toonz/convertpopup.cpp +++ b/toonz/sources/toonz/convertpopup.cpp @@ -17,6 +17,7 @@ #include "toonzqt/colorfield.h" #include "toonzqt/checkbox.h" #include "toonzqt/icongenerator.h" +#include "toonzqt/doublefield.h" // TnzLib includes #include "toonz/tscenehandle.h" @@ -26,6 +27,7 @@ #include "toutputproperties.h" #include "convert2tlv.h" #include "toonz/preferences.h" +#include "toonz/tcamera.h" // TnzCore includes #include "tsystem.h" @@ -57,6 +59,9 @@ TEnv::IntVar ConvertPopupAppendDefaultPalette( "ConvertPopupAppendDefaultPalette", 0); TEnv::IntVar ConvertPopupRemoveUnusedStyles("ConvertPopupRemoveUnusedStyles", 0); +// dpi settings for conversion to tlv +TEnv::IntVar ConvertPopupDpiMode("ConvertPopupDpiMode", 2); // Custom DPI +TEnv::DoubleVar ConvertPopupDpiValue("ConvertPopupDpiValue", 72.0); //============================================================================= // convertPopup @@ -203,7 +208,8 @@ void ConvertPopup::Converter::convertLevel( TPaletteP palette = popup->readUserProvidedPalette(); ImageUtils::convertNaa2Tlv(sourceFileFullPath, dstFileFullPath, from, to, m_parent->m_notifier, palette.getPointer(), - m_parent->m_removeUnusedStyles->isChecked()); + m_parent->m_removeUnusedStyles->isChecked(), + m_parent->m_dpiFld->getValue()); } else { convertLevelWithConvert2Tlv(sourceFileFullPath); } @@ -562,6 +568,9 @@ QFrame *ConvertPopup::createTlvSettings() { m_removeUnusedStyles = new QCheckBox(tr("Remove Unused Styles from Input Palette")); + m_dpiMode = new QComboBox(); + m_dpiFld = new DVGui::DoubleLineEdit(); + m_unpaintedFolder->setFileMode(QFileDialog::DirectoryOnly); m_unpaintedSuffix->setMaximumWidth(40); QStringList items1; @@ -587,6 +596,17 @@ QFrame *ConvertPopup::createTlvSettings() { m_palettePath->setFilters(QStringList("tpl")); // m_tolerance->setMaximumWidth(10); + QStringList dpiModes; + dpiModes << tr("Image DPI") << tr("Current Camera DPI") << tr("Custom DPI"); + m_dpiMode->addItems(dpiModes); + m_dpiMode->setToolTip(tr( + "Specify the policy for setting DPI of converted tlv. \n" + "If you select the \"Image DPI\" option and the source image does not \n" + "contain the dpi information, then the current camera dpi will be " + "used.\n")); + m_dpiMode->setCurrentIndex(ConvertPopupDpiMode); + m_dpiFld->setValue(ConvertPopupDpiValue); + QGridLayout *gridLay = new QGridLayout(); { gridLay->addWidget(new QLabel(tr("Mode:")), 0, 0, @@ -616,6 +636,11 @@ QFrame *ConvertPopup::createTlvSettings() { gridLay->addWidget(m_removeUnusedStyles, 5, 1, 1, 3); gridLay->addWidget(m_appendDefaultPalette, 6, 1, 1, 3); gridLay->addWidget(m_saveBackupToNopaint, 7, 1, 1, 3); + + gridLay->addWidget(new QLabel(tr("Dpi:")), 8, 0, + Qt::AlignRight | Qt::AlignVCenter); + gridLay->addWidget(m_dpiMode, 8, 1); + gridLay->addWidget(m_dpiFld, 8, 2); } gridLay->setColumnStretch(0, 0); gridLay->setColumnStretch(1, 1); @@ -628,6 +653,8 @@ QFrame *ConvertPopup::createTlvSettings() { SLOT(onAntialiasSelected(int))); ret = ret && connect(m_palettePath, SIGNAL(pathChanged()), this, SLOT(onPalettePathChanged())); + ret = ret && connect(m_dpiMode, SIGNAL(currentIndexChanged(int)), this, + SLOT(onDpiModeSelected(int))); assert(ret); @@ -762,6 +789,9 @@ void ConvertPopup::setFiles(const std::vector &fps) { } m_srcFilePaths = fps; + + m_imageDpi = 0.0; + if (m_srcFilePaths.size() == 1) { setWindowTitle(tr("Convert 1 Level")); m_fromFld->setEnabled(true); @@ -783,6 +813,11 @@ void ConvertPopup::setFiles(const std::vector &fps) { if (end.getNumber() > 0) m_toFld->setText(QString::number(end.getNumber())); } + + // use the image dpi for the converted tlv + const TImageInfo *ii = lrTmp->getImageInfo(); + if (ii) + m_imageDpi = ii->m_dpix; // for now, consider only the horizontal dpi } // m_fromFld->setText("1"); // m_toFld->setText(QString::number(levelTmp->getFrameCount()==-2?1:levelTmp->getFrameCount())); @@ -845,7 +880,7 @@ Convert2Tlv *ConvertPopup::makeTlvConverter(const TFilePath &sourceFilePath) { m_applyAutoclose->isChecked(), palettePath, m_tolerance->getValue(), m_antialias->currentIndex(), m_antialiasIntensity->getValue(), getTlvMode() == TlvMode_UnpaintedFromNonAA, - m_appendDefaultPalette->isChecked()); + m_appendDefaultPalette->isChecked(), m_dpiFld->getValue()); return converter; } @@ -1083,7 +1118,7 @@ void ConvertPopup::apply() { // if parameters are not ok do nothing and don't close the dialog if (!checkParameters()) return; - /*--- envにパラメータを記憶 ---*/ + // store the parameters in user env file ConvertPopupFileFormat = m_fileFormat->currentText().toStdString(); TPixel32 bgCol = m_bgColorField->getColor(); ConvertPopupBgColorR = (int)bgCol.r; @@ -1097,6 +1132,10 @@ void ConvertPopup::apply() { m_appendDefaultPalette->isChecked() ? 1 : 0; ConvertPopupRemoveUnusedStyles = m_removeUnusedStyles->isChecked() ? 1 : 0; + ConvertPopupDpiMode = m_dpiMode->currentIndex(); + if (m_dpiMode->currentIndex() == 2) // In the case of Custom DPI + ConvertPopupDpiValue = m_dpiFld->getValue(); + // parameters are ok: close the dialog first close(); @@ -1231,6 +1270,30 @@ bool ConvertPopup::isSaveTlvBackupToNopaintActive() { Folder オプションが有効 --*/ } +//------------------------------------------------------------------- + +void ConvertPopup::onDpiModeSelected(int index) { + double dpiVal; + if (index == 2) { // Custom + m_dpiFld->setEnabled(true); + dpiVal = ConvertPopupDpiValue; + } else { // Image or Camera DPI + m_dpiFld->setEnabled(false); + if (index == 1 || m_imageDpi == 0.0) { // If dpi information is not + // contained in the source, use the + // camera dpi + dpiVal = TApp::instance() + ->getCurrentScene() + ->getScene() + ->getCurrentCamera() + ->getDpi() + .x; + } else + dpiVal = m_imageDpi; + } + m_dpiFld->setValue(dpiVal); +} + //============================================================================= // ConvertPopupCommand //----------------------------------------------------------------------------- diff --git a/toonz/sources/toonz/convertpopup.h b/toonz/sources/toonz/convertpopup.h index b779a07..ef71ec9 100644 --- a/toonz/sources/toonz/convertpopup.h +++ b/toonz/sources/toonz/convertpopup.h @@ -35,6 +35,7 @@ class LineEdit; class ColorField; class ProgressDialog; class CheckBox; +class DoubleLineEdit; } namespace ImageUtils { @@ -89,6 +90,8 @@ public slots: void onFormatChanged(const QString &); void onPalettePathChanged(); + void onDpiModeSelected(int index); + protected: Convert2Tlv *makeTlvConverter(const TFilePath &sourceFilePath); bool checkParameters() const; @@ -113,6 +116,10 @@ private: QPushButton *m_okBtn, *m_cancelBtn, *m_formatOptions; + QComboBox *m_dpiMode; + DVGui::DoubleLineEdit *m_dpiFld; + double m_imageDpi; + class Converter; Converter *m_converter; diff --git a/toonz/sources/toonzlib/Naa2TlvConverter.cpp b/toonz/sources/toonzlib/Naa2TlvConverter.cpp index 50004f5..7e610b1 100644 --- a/toonz/sources/toonzlib/Naa2TlvConverter.cpp +++ b/toonz/sources/toonzlib/Naa2TlvConverter.cpp @@ -744,6 +744,14 @@ void Naa2TlvConverter::addBorderInks() // add syntethic inks: lines between two m_syntheticInkRas = new WorkRaster(lx, ly); for (int i = 0; i < lx * ly; i++) m_syntheticInkRas->pixels(0)[i] = 0; + // calculate brightness of all colors in order to decide the region on which + // the border to be added + QList colorsBrightness; + QVector::iterator c; + for (c = m_colors.begin(); c != m_colors.end(); ++c) + colorsBrightness.append((int)(*c).r * 30 + (int)(*c).g * 59 + + (int)(*c).b * 11); + int borderInkColorIndex = m_colors.count(); m_colors.append(TPixel32(255, 0, 0)); @@ -778,7 +786,9 @@ void Naa2TlvConverter::addBorderInks() // add syntethic inks: lines between two // OLD: note: we consider only regions with a lower index, to avoid // to create double border strokes // NEW: we put syntetic ink pixels in larger regions - if (m_regions[c1].pixelCount < m_regions[c].pixelCount) { + // UPDATE 2017/5/12 : we put ink on darker style + if (colorsBrightness[m_regions[c1].colorIndex] > + colorsBrightness[m_regions[c].colorIndex]) { touchesOtherRegion = true; break; } @@ -1002,7 +1012,7 @@ int Naa2TlvConverter::measureThickness(int x0, int y0) { //----------------------------------------------------------------------------- TToonzImageP Naa2TlvConverter::makeTlv(bool transparentSyntheticInks, - QList &usedStyleIds) { + QList &usedStyleIds, double dpi) { if (!m_valid || m_colors.empty() || m_regions.empty() || !m_regionRas) return TToonzImageP(); int lx = m_regionRas->getLx(); @@ -1053,15 +1063,67 @@ TToonzImageP Naa2TlvConverter::makeTlv(bool transparentSyntheticInks, outScanLine[x] = TPixelCM32(styleId, 0, 0); else if (m_syntheticInkRas->pixels(y)[x] == 1) outScanLine[x] = - TPixelCM32(transparentSyntheticInks ? 0 : styleId, styleId, 0); + TPixelCM32(transparentSyntheticInks ? 0 : styleId, 0, 0); else outScanLine[x] = TPixelCM32(0, styleId, 255); } } + struct locals { + static bool compare(const QPair &p1, const QPair &p2) { + return p1.second > p2.second; + } + + static void addPaint(QList> &list, const int paintId) { + if (paintId == 0) return; + for (int i = 0; i < list.size(); i++) + if (list[i].first == paintId) { + list[i].second += 1; + return; + } + list.append(QPair(paintId, 1)); + } + }; // locals + + // Here, expand paint area under the solid ink pixel in order to prevent the + // gap appears when the "Add Antialiasing" option is activated. + TRasterCM32P copiedRas = ras->clone(); + copiedRas->lock(); + for (int y = 0; y < ly; y++) { + TPixelCM32 *topScanLine = copiedRas->pixels((y == 0) ? y : y - 1); + TPixelCM32 *middleScanLine = copiedRas->pixels(y); + TPixelCM32 *bottomScanLine = copiedRas->pixels((y == ly - 1) ? y : y + 1); + TPixelCM32 *outScanLine = ras->pixels(y); + for (int x = 0; x < lx; x++) { + if (!middleScanLine[x].isPureInk() || middleScanLine[x].getPaint() != 0) + continue; + + int prev_x = (x == 0) ? x : x - 1; + int next_x = (x == lx - 1) ? x : x + 1; + QList> neighborPaints; + locals::addPaint(neighborPaints, topScanLine[prev_x].getPaint()); + locals::addPaint(neighborPaints, topScanLine[x].getPaint()); + locals::addPaint(neighborPaints, topScanLine[next_x].getPaint()); + locals::addPaint(neighborPaints, middleScanLine[prev_x].getPaint()); + locals::addPaint(neighborPaints, middleScanLine[next_x].getPaint()); + locals::addPaint(neighborPaints, bottomScanLine[prev_x].getPaint()); + locals::addPaint(neighborPaints, bottomScanLine[x].getPaint()); + locals::addPaint(neighborPaints, bottomScanLine[next_x].getPaint()); + qSort(neighborPaints.begin(), neighborPaints.end(), locals::compare); + + if (!neighborPaints.isEmpty()) + outScanLine[x].setPaint(neighborPaints[0].first); + } + } + copiedRas->unlock(); + TToonzImageP ti = new TToonzImage(ras, ras->getBounds()); ti->setPalette(palette); - ti->setDpi(72, 72); + + if (dpi > 0.0) // for now, accept only square pixel + ti->setDpi(dpi, dpi); + else + ti->setDpi(72, 72); return ti; } diff --git a/toonz/sources/toonzlib/convert2tlv.cpp b/toonz/sources/toonzlib/convert2tlv.cpp index 2fbed64..d537415 100644 --- a/toonz/sources/toonzlib/convert2tlv.cpp +++ b/toonz/sources/toonzlib/convert2tlv.cpp @@ -643,7 +643,8 @@ Convert2Tlv::Convert2Tlv(const TFilePath &filepath1, const TFilePath &filepath2, int from, int to, bool doAutoclose, const TFilePath &palettePath, int colorTolerance, int antialiasType, int antialiasValue, - bool isUnpaintedFromNAA, bool appendDefaultPalette) + bool isUnpaintedFromNAA, bool appendDefaultPalette, + double dpi) : m_size(0, 0) , m_level1() , m_levelIn1() @@ -660,7 +661,8 @@ Convert2Tlv::Convert2Tlv(const TFilePath &filepath1, const TFilePath &filepath2, , m_antialiasType(antialiasType) , m_antialiasValue(antialiasValue) , m_isUnpaintedFromNAA(isUnpaintedFromNAA) - , m_appendDefaultPalette(appendDefaultPalette) { + , m_appendDefaultPalette(appendDefaultPalette) + , m_dpi(dpi) { if (filepath1 != TFilePath()) { m_levelIn1 = filepath1.getParentDir() + filepath1.getLevelName(); if (outFolder != TFilePath()) @@ -886,10 +888,13 @@ bool Convert2Tlv::convertNext(std::string &errorMessage) { TRop::computeBBox(rout, bbox); timg->setSavebox(bbox); - double dpix, dpiy; - - imgIn1->getDpi(dpix, dpiy); - timg->setDpi(dpix, dpiy); + if (m_dpi > 0.0) // specify dpi in the convert popup + timg->setDpi(m_dpi, m_dpi); + else { + double dpix, dpiy; + imgIn1->getDpi(dpix, dpiy); + timg->setDpi(dpix, dpiy); + } TLevel::Iterator itaux = m_it; itaux++; diff --git a/toonz/sources/toonzqt/imageutils.cpp b/toonz/sources/toonzqt/imageutils.cpp index 8131c32..fe66dbb 100644 --- a/toonz/sources/toonzqt/imageutils.cpp +++ b/toonz/sources/toonzqt/imageutils.cpp @@ -633,7 +633,7 @@ void convert(const TFilePath &source, const TFilePath &dest, void convertNaa2Tlv(const TFilePath &source, const TFilePath &dest, const TFrameId &from, const TFrameId &to, FrameTaskNotifier *frameNotifier, TPalette *palette, - bool removeUnusedStyles) { + bool removeUnusedStyles, double dpi) { std::string dstExt = dest.getType(), srcExt = source.getType(); // Load source level structure @@ -674,8 +674,8 @@ void convertNaa2Tlv(const TFilePath &source, const TFilePath &dest, converter.process(raster); - if (TToonzImageP dstImg = - converter.makeTlv(false, usedStyleIds)) // Opaque synthetic inks + if (TToonzImageP dstImg = converter.makeTlv( + false, usedStyleIds, dpi)) // Opaque synthetic inks { if (converter.getPalette() == 0) converter.setPalette(dstImg->getPalette());