Fix png and spritesheet render (depremultiply) by turtletooth (modified) (#1844)

* Fix png and spritesheet render (depremultiply)

* move depremultiply in PngWriter
This commit is contained in:
shun-iwasawa 2018-03-06 14:00:18 +09:00 committed by Jeremy Bullock
parent b08db1990c
commit e6b1248e52
5 changed files with 82 additions and 19 deletions

View file

@ -631,6 +631,7 @@ void TImageWriter::save(const TImageP &img) {
writer->open(file, info); writer->open(file, info);
ras->lock(); ras->lock();
if (writer->getRowOrder() == Tiio::BOTTOM2TOP) { if (writer->getRowOrder() == Tiio::BOTTOM2TOP) {
if (bpp == 1 || bpp == 8 || bpp == 24 || bpp == 32 || bpp == 16) if (bpp == 1 || bpp == 8 || bpp == 24 || bpp == 32 || bpp == 16)
for (int i = 0; i < ras->getLy(); i++) for (int i = 0; i < ras->getLy(); i++)

View file

@ -14,6 +14,7 @@
#include "png.h" #include "png.h"
#include "tpixel.h" #include "tpixel.h"
#include "tpixelutils.h"
using namespace std; using namespace std;
//------------------------------------------------------------ //------------------------------------------------------------
@ -876,7 +877,11 @@ void PngWriter::writeLine(short *buffer) {
tmp = (unsigned short *)malloc((m_info.m_lx + 1) * 3); tmp = (unsigned short *)malloc((m_info.m_lx + 1) * 3);
// unsigned short tmp[10000]; // unsigned short tmp[10000];
int k = 0; 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) || \ #if defined(TNZ_MACHINE_CHANNEL_ORDER_MRGB) || \
defined(TNZ_MACHINE_CHANNEL_ORDER_RGBM) defined(TNZ_MACHINE_CHANNEL_ORDER_RGBM)
tmp[k++] = mySwap(pix->r); tmp[k++] = mySwap(pix->r);
@ -890,8 +895,8 @@ void PngWriter::writeLine(short *buffer) {
#else #else
#error "unknown channel order" #error "unknown channel order"
#endif #endif
if (m_matte) tmp[k++] = mySwap(pix->m); if (m_matte)
++pix; tmp[k++] = mySwap(pix->m); // ?? does it take care MRGB or MBGR case?
} }
png_write_row(m_png_ptr, (unsigned char *)tmp); png_write_row(m_png_ptr, (unsigned char *)tmp);
} }
@ -903,14 +908,43 @@ void PngWriter::writeLine(char *buffer) {
// TBoolProperty* alphaProp = // TBoolProperty* alphaProp =
// (TBoolProperty*)(m_properties->getProperty("Alpha Channel")); // (TBoolProperty*)(m_properties->getProperty("Alpha Channel"));
if (m_matte || m_colormap) { if (m_matte || m_colormap) {
png_bytep row_pointer = (unsigned char *)buffer; unsigned char *tmp = new unsigned char[(m_info.m_lx + 1) * 4];
png_write_row(m_png_ptr, row_pointer);
} else {
unsigned char *tmp = 0;
TPixel32 *pix = (TPixel32 *)buffer; TPixel32 *pix = (TPixel32 *)buffer;
tmp = (unsigned char *)malloc((m_info.m_lx + 1) * 3); 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 {
TPixel32 *pix = (TPixel32 *)buffer;
unsigned char *tmp = new unsigned char[(m_info.m_lx + 1) * 3];
// unsigned char tmp[10000];
int k = 0; int k = 0;
for (int j = 0; j < m_info.m_lx; j++) { for (int j = 0; j < m_info.m_lx; j++) {
// tmp = (pix->r&0xe0)|((pix->g&0xe0)>>3) | ((pix->b&0xc0)>>6); // tmp = (pix->r&0xe0)|((pix->g&0xe0)>>3) | ((pix->b&0xc0)>>6);
@ -932,6 +966,7 @@ void PngWriter::writeLine(char *buffer) {
++pix; ++pix;
} }
png_write_row(m_png_ptr, tmp); png_write_row(m_png_ptr, tmp);
delete[] tmp;
} }
} }

View file

@ -106,7 +106,7 @@ TLevelWriterSprite::~TLevelWriterSprite() {
totalHorizPadding = horizDim * horizPadding; totalHorizPadding = horizDim * horizPadding;
spriteSheetWidth = horizDim * resizedWidth + totalHorizPadding; spriteSheetWidth = horizDim * resizedWidth + totalHorizPadding;
vertDim = horizDim; 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) // (Such as 6 images needs 3 x 2 grid)
if (vertDim * vertDim - vertDim >= m_imagesResized.size()) { if (vertDim * vertDim - vertDim >= m_imagesResized.size()) {
vertDim = vertDim - 1; vertDim = vertDim - 1;
@ -130,8 +130,8 @@ TLevelWriterSprite::~TLevelWriterSprite() {
} }
} }
if (m_format != "Individual") { if (m_format != "Individual") {
QImage spriteSheet = QImage spriteSheet = QImage(spriteSheetWidth, spriteSheetHeight,
QImage(spriteSheetWidth, spriteSheetHeight, QImage::Format_ARGB32); QImage::Format_ARGB32_Premultiplied);
spriteSheet.fill(qRgba(0, 0, 0, 0)); spriteSheet.fill(qRgba(0, 0, 0, 0));
QPainter painter; QPainter painter;
painter.begin(&spriteSheet); painter.begin(&spriteSheet);
@ -229,7 +229,8 @@ void TLevelWriterSprite::save(const TImageP &img, int frameIndex) {
QByteArray ba = m_intermediateFormat.toUpper().toLatin1(); QByteArray ba = m_intermediateFormat.toUpper().toLatin1();
const char *format = ba.data(); 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; int l = qi->width(), r = 0, t = qi->height(), b = 0;
if (m_trim) { if (m_trim) {
@ -269,7 +270,7 @@ void TLevelWriterSprite::save(const TImageP &img, int frameIndex) {
if (t < m_top) m_top = t; if (t < m_top) m_top = t;
if (b > m_bottom) m_bottom = b; 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)); newQi->fill(qRgba(0, 0, 0, 0));
QPainter painter(newQi); QPainter painter(newQi);
painter.drawImage(QPoint(0, 0), *qi); painter.drawImage(QPoint(0, 0), *qi);

View file

@ -268,9 +268,9 @@ void FlipBook::addFreezeButtonToTitleBar() {
TPanel *panel = qobject_cast<TPanel *>(parentWidget()); TPanel *panel = qobject_cast<TPanel *>(parentWidget());
if (panel) { if (panel) {
TPanelTitleBar *titleBar = panel->getTitleBar(); TPanelTitleBar *titleBar = panel->getTitleBar();
m_freezeButton = new TPanelTitleBarButton(titleBar, ":Resources/pane_freeze_off.svg", m_freezeButton = new TPanelTitleBarButton(
":Resources/pane_freeze_over.svg", titleBar, ":Resources/pane_freeze_off.svg",
":Resources/pane_freeze_on.svg"); ":Resources/pane_freeze_over.svg", ":Resources/pane_freeze_on.svg");
m_freezeButton->setToolTip("Freeze"); m_freezeButton->setToolTip("Freeze");
titleBar->add(QPoint(-55, 0), m_freezeButton); titleBar->add(QPoint(-55, 0), m_freezeButton);
connect(m_freezeButton, SIGNAL(toggled(bool)), this, SLOT(freeze(bool))); 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); Level levelToPush(level, fp, fromIndex, toIndex, step);
levelToPush.m_randomAccessRead = randomAccessRead; levelToPush.m_randomAccessRead = randomAccessRead;
levelToPush.m_incrementalIndexing = incrementalIndexing; 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); m_levels.push_back(levelToPush);
// Get the frames count to be shown in this flipbook level // Get the frames count to be shown in this flipbook level
@ -1498,7 +1507,7 @@ TImageP FlipBook::getCurrentImage(int frame) {
bool randomAccessRead = false; bool randomAccessRead = false;
bool incrementalIndexing = false; bool incrementalIndexing = false;
bool premultiply = false;
if (m_xl) // is an xsheet level if (m_xl) // is an xsheet level
{ {
if (m_xl->getFrameCount() <= 0) return 0; if (m_xl->getFrameCount() <= 0) return 0;
@ -1533,6 +1542,7 @@ TImageP FlipBook::getCurrentImage(int frame) {
incrementalIndexing = m_levels[i].m_incrementalIndexing; incrementalIndexing = m_levels[i].m_incrementalIndexing;
levelName = m_levelNames[i]; levelName = m_levelNames[i];
fid = m_levels[i].flipbookIndexToLevelFrame(frameIndex); fid = m_levels[i].flipbookIndexToLevelFrame(frameIndex);
premultiply = m_levels[i].m_premultiply;
if (fid == TFrameId()) return 0; if (fid == TFrameId()) return 0;
id = levelName.toStdString() + fid.expand(TFrameId::NO_PAD) + id = levelName.toStdString() + fid.expand(TFrameId::NO_PAD) +
((m_isPreviewFx) ? "" : ::to_string(this)); ((m_isPreviewFx) ? "" : ::to_string(this));
@ -1587,6 +1597,13 @@ TImageP FlipBook::getCurrentImage(int frame) {
if (img) { if (img) {
TRasterImageP ri = ((TRasterImageP)img); TRasterImageP ri = ((TRasterImageP)img);
TToonzImageP ti = ((TToonzImageP)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' // se e' stata caricata una sottoimmagine alcuni formati in realta'
// caricano tutto il raster e fanno extract, non si ha quindi alcun // caricano tutto il raster e fanno extract, non si ha quindi alcun
// risparmio di occupazione di memoria; alloco un raster grande // risparmio di occupazione di memoria; alloco un raster grande

View file

@ -134,11 +134,20 @@ protected:
, m_toIndex(toIndex) , m_toIndex(toIndex)
, m_step(step) , m_step(step)
, m_randomAccessRead(false) , m_randomAccessRead(false)
, m_incrementalIndexing(false) {} , m_incrementalIndexing(false)
, m_premultiply(false) {}
TLevelP m_level; TLevelP m_level;
int m_fromIndex, m_toIndex, m_step; int m_fromIndex, m_toIndex, m_step;
bool m_incrementalIndexing; bool m_incrementalIndexing;
bool m_randomAccessRead; 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; TFilePath m_fp;
TFrameId flipbookIndexToLevelFrame(int index); TFrameId flipbookIndexToLevelFrame(int index);