diff --git a/toonz/sources/common/timage_io/timage_io.cpp b/toonz/sources/common/timage_io/timage_io.cpp index 05a7f44..0c0973d 100644 --- a/toonz/sources/common/timage_io/timage_io.cpp +++ b/toonz/sources/common/timage_io/timage_io.cpp @@ -631,6 +631,7 @@ void TImageWriter::save(const TImageP &img) { writer->open(file, info); ras->lock(); + if (writer->getRowOrder() == Tiio::BOTTOM2TOP) { if (bpp == 1 || bpp == 8 || bpp == 24 || bpp == 32 || bpp == 16) for (int i = 0; i < ras->getLy(); i++) diff --git a/toonz/sources/image/png/tiio_png.cpp b/toonz/sources/image/png/tiio_png.cpp index f824d5d..2da4198 100644 --- a/toonz/sources/image/png/tiio_png.cpp +++ b/toonz/sources/image/png/tiio_png.cpp @@ -14,6 +14,7 @@ #include "png.h" #include "tpixel.h" +#include "tpixelutils.h" using namespace std; //------------------------------------------------------------ @@ -876,7 +877,11 @@ void PngWriter::writeLine(short *buffer) { tmp = (unsigned short *)malloc((m_info.m_lx + 1) * 3); // unsigned short tmp[10000]; int k = 0; - for (int j = 0; j < m_info.m_lx; j++) { + for (int j = 0; j < m_info.m_lx; j++, pix++) { + // depremultiply here + TPixel64 depremult_pix(*pix); + if (m_matte && depremult_pix.m != 0) depremult(depremult_pix); + #if defined(TNZ_MACHINE_CHANNEL_ORDER_MRGB) || \ defined(TNZ_MACHINE_CHANNEL_ORDER_RGBM) tmp[k++] = mySwap(pix->r); @@ -890,8 +895,8 @@ void PngWriter::writeLine(short *buffer) { #else #error "unknown channel order" #endif - if (m_matte) tmp[k++] = mySwap(pix->m); - ++pix; + if (m_matte) + tmp[k++] = mySwap(pix->m); // ?? does it take care MRGB or MBGR case? } png_write_row(m_png_ptr, (unsigned char *)tmp); } @@ -903,14 +908,43 @@ void PngWriter::writeLine(char *buffer) { // TBoolProperty* alphaProp = // (TBoolProperty*)(m_properties->getProperty("Alpha Channel")); if (m_matte || m_colormap) { - png_bytep row_pointer = (unsigned char *)buffer; - png_write_row(m_png_ptr, row_pointer); + unsigned char *tmp = new unsigned char[(m_info.m_lx + 1) * 4]; + TPixel32 *pix = (TPixel32 *)buffer; + int k = 0; + for (int j = 0; j < m_info.m_lx; j++, pix++) { + // depremultiply here + TPixel32 depremult_pix(*pix); + if (depremult_pix.m != 0) depremult(depremult_pix); +#if defined(TNZ_MACHINE_CHANNEL_ORDER_MRGB) + tmp[k++] = depremult_pix.m; + tmp[k++] = depremult_pix.r; + tmp[k++] = depremult_pix.g; + tmp[k++] = depremult_pix.b; +#elif defined(TNZ_MACHINE_CHANNEL_ORDER_RGBM) + tmp[k++] = depremult_pix.r; + tmp[k++] = depremult_pix.g; + tmp[k++] = depremult_pix.b; + tmp[k++] = depremult_pix.m; +#elif defined(TNZ_MACHINE_CHANNEL_ORDER_MBGR) + tmp[k++] = depremult_pix.m; + tmp[k++] = depremult_pix.b; + tmp[k++] = depremult_pix.g; + tmp[k++] = depremult_pix.r; +#elif defined(TNZ_MACHINE_CHANNEL_ORDER_BGRM) + tmp[k++] = depremult_pix.b; + tmp[k++] = depremult_pix.g; + tmp[k++] = depremult_pix.r; + tmp[k++] = depremult_pix.m; +#else +#error "unknown channel order" +#endif + } + png_write_row(m_png_ptr, tmp); + delete[] tmp; } else { - unsigned char *tmp = 0; TPixel32 *pix = (TPixel32 *)buffer; - tmp = (unsigned char *)malloc((m_info.m_lx + 1) * 3); + unsigned char *tmp = new unsigned char[(m_info.m_lx + 1) * 3]; - // unsigned char tmp[10000]; int k = 0; for (int j = 0; j < m_info.m_lx; j++) { // tmp = (pix->r&0xe0)|((pix->g&0xe0)>>3) | ((pix->b&0xc0)>>6); @@ -932,6 +966,7 @@ void PngWriter::writeLine(char *buffer) { ++pix; } png_write_row(m_png_ptr, tmp); + delete[] tmp; } } diff --git a/toonz/sources/image/sprite/tiio_sprite.cpp b/toonz/sources/image/sprite/tiio_sprite.cpp index 78b5b82..bb13bb1 100644 --- a/toonz/sources/image/sprite/tiio_sprite.cpp +++ b/toonz/sources/image/sprite/tiio_sprite.cpp @@ -106,7 +106,7 @@ TLevelWriterSprite::~TLevelWriterSprite() { totalHorizPadding = horizDim * horizPadding; spriteSheetWidth = horizDim * resizedWidth + totalHorizPadding; vertDim = horizDim; - // Figure out if there is one row too many + // Figure out if there is one row too many // (Such as 6 images needs 3 x 2 grid) if (vertDim * vertDim - vertDim >= m_imagesResized.size()) { vertDim = vertDim - 1; @@ -130,8 +130,8 @@ TLevelWriterSprite::~TLevelWriterSprite() { } } if (m_format != "Individual") { - QImage spriteSheet = - QImage(spriteSheetWidth, spriteSheetHeight, QImage::Format_ARGB32); + QImage spriteSheet = QImage(spriteSheetWidth, spriteSheetHeight, + QImage::Format_ARGB32_Premultiplied); spriteSheet.fill(qRgba(0, 0, 0, 0)); QPainter painter; painter.begin(&spriteSheet); @@ -229,7 +229,8 @@ void TLevelWriterSprite::save(const TImageP &img, int frameIndex) { QByteArray ba = m_intermediateFormat.toUpper().toLatin1(); const char *format = ba.data(); - QImage *qi = new QImage((uint8_t *)buffer, m_lx, m_ly, QImage::Format_ARGB32); + QImage *qi = new QImage((uint8_t *)buffer, m_lx, m_ly, + QImage::Format_ARGB32_Premultiplied); int l = qi->width(), r = 0, t = qi->height(), b = 0; if (m_trim) { @@ -269,7 +270,7 @@ void TLevelWriterSprite::save(const TImageP &img, int frameIndex) { if (t < m_top) m_top = t; if (b > m_bottom) m_bottom = b; } - QImage *newQi = new QImage(m_lx, m_ly, QImage::Format_ARGB32); + QImage *newQi = new QImage(m_lx, m_ly, QImage::Format_ARGB32_Premultiplied); newQi->fill(qRgba(0, 0, 0, 0)); QPainter painter(newQi); painter.drawImage(QPoint(0, 0), *qi); diff --git a/toonz/sources/toonz/flipbook.cpp b/toonz/sources/toonz/flipbook.cpp index baefdfb..5b24cfa 100644 --- a/toonz/sources/toonz/flipbook.cpp +++ b/toonz/sources/toonz/flipbook.cpp @@ -268,9 +268,9 @@ void FlipBook::addFreezeButtonToTitleBar() { TPanel *panel = qobject_cast(parentWidget()); if (panel) { TPanelTitleBar *titleBar = panel->getTitleBar(); - m_freezeButton = new TPanelTitleBarButton(titleBar, ":Resources/pane_freeze_off.svg", - ":Resources/pane_freeze_over.svg", - ":Resources/pane_freeze_on.svg"); + m_freezeButton = new TPanelTitleBarButton( + titleBar, ":Resources/pane_freeze_off.svg", + ":Resources/pane_freeze_over.svg", ":Resources/pane_freeze_on.svg"); m_freezeButton->setToolTip("Freeze"); titleBar->add(QPoint(-55, 0), m_freezeButton); connect(m_freezeButton, SIGNAL(toggled(bool)), this, SLOT(freeze(bool))); @@ -1136,6 +1136,15 @@ void FlipBook::setLevel(const TFilePath &fp, TPalette *palette, int from, Level levelToPush(level, fp, fromIndex, toIndex, step); levelToPush.m_randomAccessRead = randomAccessRead; levelToPush.m_incrementalIndexing = incrementalIndexing; + + int formatIdx = Preferences::instance()->matchLevelFormat(fp); + if (formatIdx >= 0 && + Preferences::instance() + ->levelFormat(formatIdx) + .m_options.m_premultiply) { + levelToPush.m_premultiply = true; + } + m_levels.push_back(levelToPush); // Get the frames count to be shown in this flipbook level @@ -1498,7 +1507,7 @@ TImageP FlipBook::getCurrentImage(int frame) { bool randomAccessRead = false; bool incrementalIndexing = false; - + bool premultiply = false; if (m_xl) // is an xsheet level { if (m_xl->getFrameCount() <= 0) return 0; @@ -1533,6 +1542,7 @@ TImageP FlipBook::getCurrentImage(int frame) { incrementalIndexing = m_levels[i].m_incrementalIndexing; levelName = m_levelNames[i]; fid = m_levels[i].flipbookIndexToLevelFrame(frameIndex); + premultiply = m_levels[i].m_premultiply; if (fid == TFrameId()) return 0; id = levelName.toStdString() + fid.expand(TFrameId::NO_PAD) + ((m_isPreviewFx) ? "" : ::to_string(this)); @@ -1587,6 +1597,13 @@ TImageP FlipBook::getCurrentImage(int frame) { if (img) { TRasterImageP ri = ((TRasterImageP)img); TToonzImageP ti = ((TToonzImageP)img); + if (premultiply) { + if (ri) + TRop::premultiply(ri->getRaster()); + else if (ti) + TRop::premultiply(ti->getRaster()); + } + // se e' stata caricata una sottoimmagine alcuni formati in realta' // caricano tutto il raster e fanno extract, non si ha quindi alcun // risparmio di occupazione di memoria; alloco un raster grande diff --git a/toonz/sources/toonz/flipbook.h b/toonz/sources/toonz/flipbook.h index 53933b7..97a0cf6 100644 --- a/toonz/sources/toonz/flipbook.h +++ b/toonz/sources/toonz/flipbook.h @@ -134,11 +134,20 @@ protected: , m_toIndex(toIndex) , m_step(step) , m_randomAccessRead(false) - , m_incrementalIndexing(false) {} + , m_incrementalIndexing(false) + , m_premultiply(false) {} TLevelP m_level; int m_fromIndex, m_toIndex, m_step; bool m_incrementalIndexing; bool m_randomAccessRead; + + // Specified if the level is needed to be premultiplied on display. + // It will be true for the files of which the "premultiply" option is + // activated in the Preferences > Loading > "Level Settings by File Format". + // By default, PNG will be loaded with being premultiplied so that it will + // be displayed properly. + bool m_premultiply; + TFilePath m_fp; TFrameId flipbookIndexToLevelFrame(int index);