diff --git a/toonz/sources/common/tiio/tiio_bmp.cpp b/toonz/sources/common/tiio/tiio_bmp.cpp index 243a1f7..a20f164 100644 --- a/toonz/sources/common/tiio/tiio_bmp.cpp +++ b/toonz/sources/common/tiio/tiio_bmp.cpp @@ -598,6 +598,9 @@ public: void flush() override { fflush(m_chan); } void writeLine(char *buffer) override; + + // for now opentoonz does not support bmp format with alpha channel + bool writeAlphaSupported() const override { return false; } }; //--------------------------------------------------------- diff --git a/toonz/sources/common/tiio/tiio_jpg.cpp b/toonz/sources/common/tiio/tiio_jpg.cpp index 5410ad8..25a454d 100644 --- a/toonz/sources/common/tiio/tiio_jpg.cpp +++ b/toonz/sources/common/tiio/tiio_jpg.cpp @@ -273,6 +273,9 @@ public: } jpeg_write_scanlines(&m_cinfo, m_buffer, 1); } + + // jpeg format does not support alpha channel + bool writeAlphaSupported() const override { return false; } }; //---- diff --git a/toonz/sources/common/timage_io/timage_io.cpp b/toonz/sources/common/timage_io/timage_io.cpp index c9fb84c..bb2ded5 100644 --- a/toonz/sources/common/timage_io/timage_io.cpp +++ b/toonz/sources/common/timage_io/timage_io.cpp @@ -11,6 +11,7 @@ #include "trasterimage.h" #include "tiio.h" #include "tfilepath_io.h" +#include "tpixelutils.h" // boost includes #include @@ -630,6 +631,19 @@ void TImageWriter::save(const TImageP &img) { writer->open(file, info); + // add background colors for non alpha-enabled image types + if ((ras32 || ras64) && !writer->writeAlphaSupported() && + TImageWriter::getBackgroundColor() != TPixel::Black) { + if (ras32) + TRop::addBackground(ras, TImageWriter::getBackgroundColor()); + else { // ras64 + TRaster64P bgRas(ras->getSize()); + bgRas->fill(toPixel64(TImageWriter::getBackgroundColor())); + TRop::over(bgRas, ras); + ras = bgRas; + } + } + ras->lock(); if (writer->getRowOrder() == Tiio::BOTTOM2TOP) { @@ -745,6 +759,18 @@ void TImageWriter::save(const TFilePath &path, const TImageP &image) { } //=========================================================== +// Background color for saving ransparent pixel to the format not +// supporting alpha channel. Specified in the preferences. + +TPixel32 TImageWriter::m_backgroundColor; + +void TImageWriter::setBackgroundColor(TPixel32 color) { + m_backgroundColor = color; +} + +TPixel32 TImageWriter::getBackgroundColor() { return m_backgroundColor; } + +//=========================================================== // // funzioni per la registrazione dei formati (chiamate dal Plugin) // diff --git a/toonz/sources/image/png/tiio_png.cpp b/toonz/sources/image/png/tiio_png.cpp index 5b44efe..0ae4f7b 100644 --- a/toonz/sources/image/png/tiio_png.cpp +++ b/toonz/sources/image/png/tiio_png.cpp @@ -760,6 +760,8 @@ public: void flush() override; bool write64bitSupported() const override { return true; } + // m_matte is set to "Alpha Channel" property value in the function open() + bool writeAlphaSupported() const override { return m_matte; }; }; //--------------------------------------------------------- diff --git a/toonz/sources/image/sgi/filesgi.cpp b/toonz/sources/image/sgi/filesgi.cpp index a5638f8..9542f19 100644 --- a/toonz/sources/image/sgi/filesgi.cpp +++ b/toonz/sources/image/sgi/filesgi.cpp @@ -1075,6 +1075,12 @@ public: void setProperties(TPropertyGroup *properties); + // m_header->zsize is updated with "Bits Per Pixel" property value in the + // function open() + bool writeAlphaSupported() const override { + return m_header && (m_header->zsize == 4); + } + private: // not implemented SgiWriter(const SgiWriter &); diff --git a/toonz/sources/image/tga/tiio_tga.cpp b/toonz/sources/image/tga/tiio_tga.cpp index 07810f7..8eaadc2 100644 --- a/toonz/sources/image/tga/tiio_tga.cpp +++ b/toonz/sources/image/tga/tiio_tga.cpp @@ -609,6 +609,12 @@ public: void writeLine32rle(char *buffer); void writeLine(char *buffer) override { (this->*m_writeLineProc)(buffer); } + + // m_header.ImagePixelSize is set to "Bits Per Pixel" property value + // in the function open() + bool writeAlphaSupported() const override { + return m_header.ImagePixelSize == 32; + } }; //------------------------------------------------------------ diff --git a/toonz/sources/image/tif/tiio_tif.cpp b/toonz/sources/image/tif/tiio_tif.cpp index 7a758d6..f8cec50 100644 --- a/toonz/sources/image/tif/tiio_tif.cpp +++ b/toonz/sources/image/tif/tiio_tif.cpp @@ -770,6 +770,11 @@ public: void flush() override; Tiio::RowOrder getRowOrder() const override { return m_rowOrder; } + + // m_bpp is set to "Bits Per Pixel" property value in the function open() + bool writeAlphaSupported() const override { + return (m_bpp == 32 || m_bpp == 64); + } }; //------------------------------------------------------------ diff --git a/toonz/sources/include/tiio.h b/toonz/sources/include/tiio.h index b8e655c..e2bb7a2 100644 --- a/toonz/sources/include/tiio.h +++ b/toonz/sources/include/tiio.h @@ -106,6 +106,7 @@ public: virtual RowOrder getRowOrder() const { return BOTTOM2TOP; } virtual bool write64bitSupported() const { return false; } + virtual bool writeAlphaSupported() const { return true; } void setProperties(TPropertyGroup *properties); diff --git a/toonz/sources/include/timage_io.h b/toonz/sources/include/timage_io.h index d6b99d0..07fecf3 100644 --- a/toonz/sources/include/timage_io.h +++ b/toonz/sources/include/timage_io.h @@ -205,6 +205,10 @@ typedef TImageWriter *TImageWriterCreateProc(const TFilePath &path); class DVAPI TImageWriter : public TSmartObject { DECLARE_CLASS_CODE + // Background color for saving transparent pixel to the format not + // supporting alpha channel. Specified in the preferences. + static TPixel32 m_backgroundColor; + protected: // std::fstream m_stream; TFilePath m_path; @@ -237,6 +241,9 @@ public: static void define(QString extension, TImageWriterCreateProc *proc, bool isRenderFormat); + + static void setBackgroundColor(TPixel32 color); + static TPixel32 getBackgroundColor(); }; //----------------------------------------------------------- diff --git a/toonz/sources/include/toonz/preferences.h b/toonz/sources/include/toonz/preferences.h index 6818966..2dc09f0 100644 --- a/toonz/sources/include/toonz/preferences.h +++ b/toonz/sources/include/toonz/preferences.h @@ -306,6 +306,11 @@ public: void setIgnoreImageDpi(bool on); bool isIgnoreImageDpiEnabled() const { return m_ignoreImageDpi; } + // Saving tab + + void setRasterBackgroundColor(const TPixel32 &color); + TPixel getRasterBackgroundColor() const { return m_rasterBackgroundColor; } + // Drawing tab void setScanLevelType(std::string s); @@ -714,7 +719,7 @@ private: QString m_cursorBrushStyle; bool m_cursorOutlineEnabled = false; - TPixel32 m_currentColumnColor; + TPixel32 m_currentColumnColor, m_rasterBackgroundColor; bool m_enableWinInk = false; bool m_useOnionColorsForShiftAndTraceGhosts = false; diff --git a/toonz/sources/toonz/preferencespopup.cpp b/toonz/sources/toonz/preferencespopup.cpp index 53c9dda..73c23e4 100644 --- a/toonz/sources/toonz/preferencespopup.cpp +++ b/toonz/sources/toonz/preferencespopup.cpp @@ -1244,6 +1244,14 @@ void PreferencesPopup::onEnableWinInkChanged(int index) { m_pref->enableWinInk(index == Qt::Checked); } +//--------------------------------------------------------------------------------------- + +void PreferencesPopup::onRasterBackgroundColorChanged(const TPixel32 &color, + bool isDragging) { + if (isDragging) return; + m_pref->setRasterBackgroundColor(color); +} + //********************************************************************************** // PrefencesPopup's constructor //********************************************************************************** @@ -1399,6 +1407,12 @@ PreferencesPopup::PreferencesPopup() m_importPolicy = new QComboBox; + //--- Saving ------------------------------ + categoryList->addItem(tr("Saving")); + + ColorField *rasterBackgroundColor = + new ColorField(this, false, m_pref->getRasterBackgroundColor()); + //--- Import/Export ------------------------------ categoryList->addItem(tr("Import/Export")); m_ffmpegPathFileFld = new DVGui::FileField(this, QString("")); @@ -2247,6 +2261,37 @@ PreferencesPopup::PreferencesPopup() loadingBox->setLayout(loadingFrameLay); stackedWidget->addWidget(loadingBox); + //--- Saving -------------------------- + QWidget *savingBox = new QWidget(this); + QVBoxLayout *savingFrameLay = new QVBoxLayout(); + savingFrameLay->setMargin(15); + savingFrameLay->setSpacing(10); + { + QLabel *matteColorLabel = + new QLabel(tr("Matte color is used for background when overwriting " + "raster levels with transparent pixels\nin non " + "alpha-enabled image format."), + this); + savingFrameLay->addWidget(matteColorLabel, 0, Qt::AlignLeft); + + QGridLayout *savingGridLay = new QGridLayout(); + savingGridLay->setVerticalSpacing(10); + savingGridLay->setHorizontalSpacing(15); + savingGridLay->setMargin(0); + { + savingGridLay->addWidget(new QLabel(tr("Matte color: "), this), 0, 0, + Qt::AlignRight); + savingGridLay->addWidget(rasterBackgroundColor, 0, 1, Qt::AlignLeft); + } + savingGridLay->setColumnStretch(0, 0); + savingGridLay->setColumnStretch(1, 1); + savingFrameLay->addLayout(savingGridLay, 0); + + savingFrameLay->addStretch(1); + } + savingBox->setLayout(savingFrameLay); + stackedWidget->addWidget(savingBox); + //--- Import/Export -------------------------- QWidget *ioBox = new QWidget(this); QVBoxLayout *ioLay = new QVBoxLayout(); @@ -2839,6 +2884,12 @@ PreferencesPopup::PreferencesPopup() SIGNAL(importPolicyChanged(int)), this, SLOT(onImportPolicyExternallyChanged(int))); + //--- Saving ---------------------- + ret = ret && + connect(rasterBackgroundColor, + SIGNAL(colorChanged(const TPixel32 &, bool)), + SLOT(onRasterBackgroundColorChanged(const TPixel32 &, bool))); + //--- Import/Export ---------------------- ret = ret && connect(m_ffmpegPathFileFld, SIGNAL(pathChanged()), this, SLOT(onFfmpegPathChanged())); diff --git a/toonz/sources/toonz/preferencespopup.h b/toonz/sources/toonz/preferencespopup.h index d53ab77..02e1d61 100644 --- a/toonz/sources/toonz/preferencespopup.h +++ b/toonz/sources/toonz/preferencespopup.h @@ -220,6 +220,7 @@ private slots: void onCursorOutlineChanged(int); void onCurrentColumnDataChanged(const TPixel32 &, bool isDragging); void onEnableWinInkChanged(int index); + void onRasterBackgroundColorChanged(const TPixel32 &, bool isDragging); }; //********************************************************************************** diff --git a/toonz/sources/toonz/rendercommand.cpp b/toonz/sources/toonz/rendercommand.cpp index 85e7925..8424092 100644 --- a/toonz/sources/toonz/rendercommand.cpp +++ b/toonz/sources/toonz/rendercommand.cpp @@ -512,13 +512,16 @@ void RenderCommand::rasterRender(bool isPreview) { TPixel32 currBgColor = scene->getProperties()->getBgColor(); m_priorBgColor = currBgColor; - // fixes background colors for non alpha-enabled export types (eventually + // fixes background colors for non alpha-enabled movie types (eventually // transparent gif would be good) - if (ext == "jpg" || ext == "avi" || ext == "bmp" || ext == "mp4" || - ext == "webm" || ext == "gif") { - currBgColor.m = 255; + currBgColor.m = 255; + if (isMovieType(ext)) { scene->getProperties()->setBgColor(currBgColor); } + // for non alpha-enabled images (like jpg), background color will be inserted + // in TImageWriter::save() (see timage_io.cpp) + else + TImageWriter::setBackgroundColor(currBgColor); // Extract output properties TOutputProperties *prop = isPreview @@ -618,6 +621,10 @@ TPixel32 RenderCommand::m_priorBgColor; void RenderCommand::resetBgColor() { ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene(); scene->getProperties()->setBgColor(m_priorBgColor); + + // revert background color settings + TImageWriter::setBackgroundColor( + Preferences::instance()->getRasterBackgroundColor()); } //=================================================================== diff --git a/toonz/sources/toonzlib/preferences.cpp b/toonz/sources/toonzlib/preferences.cpp index 8399b3c..79b498b 100644 --- a/toonz/sources/toonzlib/preferences.cpp +++ b/toonz/sources/toonzlib/preferences.cpp @@ -19,6 +19,7 @@ #include "tundo.h" #include "tbigmemorymanager.h" #include "tfilepath.h" +#include "timage_io.h" // Qt includes #include @@ -345,7 +346,8 @@ Preferences::Preferences() , m_cursorOutlineEnabled(true) , m_currentColumnColor(TPixel::Black) , m_enableWinInk(false) - , m_useOnionColorsForShiftAndTraceGhosts(false) { + , m_useOnionColorsForShiftAndTraceGhosts(false) + , m_rasterBackgroundColor(TPixel::White) { TCamera camera; m_defLevelType = PLI_XSHLEVEL; m_defLevelWidth = camera.getSize().lx; @@ -721,6 +723,9 @@ Preferences::Preferences() m_currentColumnColor = TPixel32(r, g, b); getValue(*m_settings, "winInkEnabled", m_enableWinInk); + + getValue(*m_settings, "rasterBackgroundColor", m_rasterBackgroundColor); + TImageWriter::setBackgroundColor(m_rasterBackgroundColor); } //----------------------------------------------------------------- @@ -1755,3 +1760,16 @@ void Preferences::enableWinInk(bool on) { m_enableWinInk = on; m_settings->setValue("winInkEnabled", on ? "1" : "0"); } + +void Preferences::setRasterBackgroundColor(const TPixel32 &color) { + m_rasterBackgroundColor = color; + TImageWriter::setBackgroundColor(m_rasterBackgroundColor); + m_settings->setValue("rasterBackgroundColor_R", + QString::number((int)color.r)); + m_settings->setValue("rasterBackgroundColor_G", + QString::number((int)color.g)); + m_settings->setValue("rasterBackgroundColor_B", + QString::number((int)color.b)); + m_settings->setValue("rasterBackgroundColor_M", + QString::number((int)color.m)); +} \ No newline at end of file