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:
shun-iwasawa 2017-05-19 18:01:43 +09:00 committed by masafumi-inoue
parent e33f9a51d2
commit 1584bbb473
8 changed files with 160 additions and 20 deletions

View file

@ -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();

View file

@ -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);

View file

@ -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);

View file

@ -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
//-----------------------------------------------------------------------------

View file

@ -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;

View file

@ -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,14 +1063,66 @@ 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);
if (dpi > 0.0) // for now, accept only square pixel
ti->setDpi(dpi, dpi);
else
ti->setDpi(72, 72);
return ti;

View file

@ -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);
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++;

View file

@ -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());