Fixes on convert feature from NAA raster images to TLV (#1203)
* prevent the gap on anti-aliased * add dpi settings
This commit is contained in:
parent
e33f9a51d2
commit
1584bbb473
8 changed files with 160 additions and 20 deletions
|
@ -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();
|
||||
|
|
|
@ -146,7 +146,8 @@ public:
|
|||
return -1;
|
||||
}
|
||||
|
||||
TToonzImageP makeTlv(bool transparentSyntheticInks, QList<int> &usedStyleIds);
|
||||
TToonzImageP makeTlv(bool transparentSyntheticInks, QList<int> &usedStyleIds,
|
||||
double dpi = 0.0);
|
||||
|
||||
TVectorImageP vectorize(const TToonzImageP &ti);
|
||||
TVectorImageP vectorize(const TRaster32P &ras);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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<TFilePath> &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<TFilePath> &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
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -744,6 +744,14 @@ void Naa2TlvConverter::addBorderInks() // add syntethic inks: lines between two
|
|||
m_syntheticInkRas = new WorkRaster<unsigned char>(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<int> colorsBrightness;
|
||||
QVector<TPixel32>::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<int> &usedStyleIds) {
|
||||
QList<int> &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<int, int> &p1, const QPair<int, int> &p2) {
|
||||
return p1.second > p2.second;
|
||||
}
|
||||
|
||||
static void addPaint(QList<QPair<int, int>> &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<int, int>(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<QPair<int, int>> 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;
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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());
|
||||
|
|
Loading…
Reference in a new issue