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:
parent
b08db1990c
commit
e6b1248e52
5 changed files with 82 additions and 19 deletions
|
@ -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++)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue