From a4895cd534df8336199bbdba960162c41179a390 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Sun, 19 Aug 2018 21:15:25 -0400 Subject: [PATCH 1/8] Teach PRPShop about PNG compressed mipmaps --- src/PrpShop/PRP/Surface/QMipmap.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/PrpShop/PRP/Surface/QMipmap.cpp b/src/PrpShop/PRP/Surface/QMipmap.cpp index d7d75d8..e088ddb 100644 --- a/src/PrpShop/PRP/Surface/QMipmap.cpp +++ b/src/PrpShop/PRP/Surface/QMipmap.cpp @@ -196,6 +196,19 @@ QString getCompressionText(plBitmap* tex) case plBitmap::kAInten88: return "JPEG (Alpha+Greyscale)"; } + } else if (tex->getCompressionType() == plBitmap::kPNGCompression) { + switch (tex->getARGBType()) { + case plBitmap::kRGB8888: + return "PNG (ARGB8888)"; + case plBitmap::kRGB4444: + return "PNG (ARGB4444)"; + case plBitmap::kRGB1555: + return "PNG (ARGB1555)"; + case plBitmap::kInten8: + return "PNG (Greyscale)"; + case plBitmap::kAInten88: + return "PNG (Alpha+Greyscale)"; + } } else { switch (tex->getARGBType()) { case plBitmap::kRGB8888: From 6f82f2b0ef5664ad3f845c8a6e6eb30a7e1a7bdb Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Sun, 19 Aug 2018 21:17:18 -0400 Subject: [PATCH 2/8] Fix non-DXT image channels All Plasma image data, other than DXT, is stored as BGR in plMipmap --- src/PrpShop/PRP/Surface/QMipmap.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/PrpShop/PRP/Surface/QMipmap.cpp b/src/PrpShop/PRP/Surface/QMipmap.cpp index e088ddb..76daf65 100644 --- a/src/PrpShop/PRP/Surface/QMipmap.cpp +++ b/src/PrpShop/PRP/Surface/QMipmap.cpp @@ -82,7 +82,7 @@ void QTextureBox::setTexture(plMipmap* tex, int level) fImageData = new unsigned char[size]; tex->DecompressImage(level, fImageData, size); - if (tex->getCompressionType() != plMipmap::kUncompressed) { + if (tex->getCompressionType() == plMipmap::kDirectXCompression) { // Manipulate the data from RGBA to BGRA unsigned int* dp = (unsigned int*)fImageData; for (size_t i=0; i(data); + for (size_t i=0; i> 16 + | (*dp & 0x000000FF) << 16; + dp++; + } +} + static void makeJColorSurface(const plMipmap* tex, hsStream* S) { if (tex->getCompressionType() != plBitmap::kJPEGCompression) { @@ -370,6 +381,7 @@ static void makeJColorSurface(const plMipmap* tex, hsStream* S) // Strip down data to 24 bit color unsigned char* data = new unsigned char[dds.fLinearSize]; tex->extractColorData(data, dds.fLinearSize); + swapColorChannels(data, dds.fLinearSize); dds.setData(dds.fLinearSize, data); delete[] data; @@ -428,6 +440,7 @@ static bool getJColorSurface(const plDDSurface& dds, plMipmap* tex) tex->Create(dds.fWidth, dds.fHeight, 0, plBitmap::kJPEGCompression, plBitmap::kRGB8888); tex->setColorData(dds.getData(), dds.getDataSize()); + swapColorChannels(reinterpret_cast(tex->getImageData()), dds.getDataSize()); return true; } From c982d809ba84d1e1b22c715985c31360eddae32a Mon Sep 17 00:00:00 2001 From: Joseph Davies Date: Fri, 7 Sep 2018 21:16:59 -0700 Subject: [PATCH 3/8] Improve MipMap Import/Export feature. --- src/PrpShop/PRP/Surface/QMipmap.cpp | 315 +++++++++++----------------- src/PrpShop/PRP/Surface/QMipmap.h | 6 +- 2 files changed, 128 insertions(+), 193 deletions(-) diff --git a/src/PrpShop/PRP/Surface/QMipmap.cpp b/src/PrpShop/PRP/Surface/QMipmap.cpp index 76daf65..785252a 100644 --- a/src/PrpShop/PRP/Surface/QMipmap.cpp +++ b/src/PrpShop/PRP/Surface/QMipmap.cpp @@ -29,6 +29,8 @@ #include #include "QLinkLabel.h" #include "QPlasmaUtils.h" +#include +#include /* Helpers */ static QString getExportDir() @@ -48,6 +50,33 @@ static void setExportDir(const QString& filename) settings.setValue("ExportDir", dir.absolutePath()); } +unsigned char* getTextureData(plMipmap *tex, size_t level=0) +{ + unsigned char *imageData; + + if (level >= tex->getNumLevels()) + level = tex->getNumLevels() - 1; + + size_t size = tex->GetUncompressedSize(level); + imageData = new unsigned char[size]; + tex->DecompressImage(level, imageData, size); + + if (tex->getCompressionType() == plMipmap::kDirectXCompression) { + // Manipulate the data from RGBA to BGRA + unsigned int* dp = (unsigned int*)imageData; + for (size_t i = 0; i < size; i += 4) { + //unsigned int alpha = doAlpha ? (*dp & 0xFF000000) : 0xFF000000; + *dp = (*dp & 0xFF000000) + | (*dp & 0x00FF0000) >> 16 + | (*dp & 0x0000FF00) + | (*dp & 0x000000FF) << 16; + dp++; + } + } + + return imageData; +} + /* QTextureBox */ QTextureBox::~QTextureBox() { @@ -68,8 +97,6 @@ void QTextureBox::setTexture(plMipmap* tex, int level) return; } - if (level >= (int)tex->getNumLevels()) - level = tex->getNumLevels() - 1; if (level < 0) { fImage = NULL; fImageData = NULL; @@ -78,22 +105,7 @@ void QTextureBox::setTexture(plMipmap* tex, int level) return; } - size_t size = tex->GetUncompressedSize(level); - fImageData = new unsigned char[size]; - tex->DecompressImage(level, fImageData, size); - - if (tex->getCompressionType() == plMipmap::kDirectXCompression) { - // Manipulate the data from RGBA to BGRA - unsigned int* dp = (unsigned int*)fImageData; - for (size_t i=0; i> 16 - | (*dp & 0x0000FF00) - | (*dp & 0x000000FF) << 16; - dp++; - } - } + fImageData = getTextureData(tex, level); fImage = new QImage(fImageData, tex->getLevelWidth(level), tex->getLevelHeight(level), QImage::Format_ARGB32); resize(tex->getLevelWidth(level), tex->getLevelHeight(level)); @@ -314,10 +326,8 @@ QMipmap::QMipmap(plCreatable* pCre, QWidget* parent) fPreviewLink->setCreatable(tex, tr("Preview")); fPreviewLink->setForceType(kPreviewMipmap); - QLinkLabel* xDDSLink = new QLinkLabel(tr("Export DDS..."), this); - QLinkLabel* iDDSLink = new QLinkLabel(tr("Import DDS..."), this); - QLinkLabel* xJPGLink = new QLinkLabel(tr("Export Jpeg..."), this); - QLinkLabel* iJPGLink = new QLinkLabel(tr("Import Jpeg..."), this); + QLinkLabel* xPort = new QLinkLabel(tr("Export Image..."), this); + QLinkLabel* iPort = new QLinkLabel(tr("Import Image..."), this); QGridLayout* layout = new QGridLayout(this); layout->setContentsMargins(8, 8, 8, 8); @@ -325,23 +335,11 @@ QMipmap::QMipmap(plCreatable* pCre, QWidget* parent) layout->addWidget(grpProps, 1, 0, 1, 2); layout->addWidget(fPreviewLink, 2, 0, 1, 2); layout->addItem(new QSpacerItem(0, 8, QSizePolicy::Minimum, QSizePolicy::Minimum), 3, 0, 1, 2); - layout->addWidget(xDDSLink, 4, 0); - layout->addWidget(iDDSLink, 5, 0); - layout->addWidget(xJPGLink, 4, 1); - layout->addWidget(iJPGLink, 5, 1); - - if (tex->getCompressionType() == plBitmap::kJPEGCompression) { - xDDSLink->setEnabled(false); - xJPGLink->setEnabled(true); - } else { - xDDSLink->setEnabled(true); - xJPGLink->setEnabled(false); - } + layout->addWidget(xPort, 4, 0); + layout->addWidget(iPort, 5, 0); - connect(xDDSLink, &QLinkLabel::activated, this, &QMipmap::onExportDDS); - connect(xJPGLink, &QLinkLabel::activated, this, &QMipmap::onExportJPEG); - connect(iDDSLink, &QLinkLabel::activated, this, &QMipmap::onImportDDS); - connect(iJPGLink, &QLinkLabel::activated, this, &QMipmap::onImportJPEG); + connect(xPort, &QLinkLabel::activated, this, &QMipmap::onExportImage); + connect(iPort, &QLinkLabel::activated, this, &QMipmap::onImportImage); } static void swapColorChannels(unsigned char* data, size_t size) @@ -473,186 +471,125 @@ static bool getJAlphaSurface(const plDDSurface& dds, plMipmap* tex) return true; } -void QMipmap::onExportDDS() -{ - plMipmap* tex = plMipmap::Convert(fCreatable); - QString filename = st2qstr(tex->getKey()->getName()) - .replace(QRegularExpression("[?:/\\*\"<>|]"), "_"); - filename = QFileDialog::getSaveFileName(this, tr("Export DDS"), getExportDir() + "/" + filename, - "DDS Files (*.dds)"); - if (filename.isEmpty()) - return; - - hsFileStream S; - if (!S.open(qstr2st(filename), fmCreate)) { - QMessageBox::critical(this, tr("Error exporting DDS"), - tr("Error: Could not open file %1 for writing").arg(filename), - QMessageBox::Ok); - return; - } - try { - plDDSurface dds; - dds.setFromMipmap(tex); - dds.write(&S); - } catch (hsException& ex) { - QMessageBox::critical(this, tr("Error exporting DDS"), - QString::fromUtf8(ex.what()), QMessageBox::Ok); - } - S.close(); - - setExportDir(filename); -} - -void QMipmap::onExportJPEG() -{ +void QMipmap::onExportImage() { QString exportDir = getExportDir(); - plMipmap* tex = plMipmap::Convert(fCreatable); + exportDir.append("/" + st2qstr(tex->getKey()->getName()) .replace(QRegularExpression("[?:/\\*\"<>|]"), "_")); - QString filter = tex->isImageJPEG() ? "JPEG Files (*.jpg)" : "DDS Files (*.dds)"; - QString filename = QFileDialog::getSaveFileName(this, tr("Export JPEG Image"), - exportDir, filter); + QString filter = tr("DDS Files (*.dds);;JPEG Files (*.jpg *.jpeg);;PNG Files (*.png)"); + QString filename = QFileDialog::getSaveFileName(this, tr("Export Image"), exportDir, filter); + if (filename.isEmpty()) return; - exportDir.append("_ALPHA"); - filter = tex->isAlphaJPEG() ? "JPEG Files (*.jpg)" : "DDS Files (*.dds)"; - QString alphaFname = QFileDialog::getSaveFileName(this, tr("Export JPEG Alpha"), - exportDir, filter); - if (alphaFname.isEmpty()) - return; + QString file_ext = QFileInfo(filename).suffix(); + if (file_ext == "dds") { + hsFileStream S; + if (!S.open(qstr2st(filename), fmCreate)) { + QMessageBox::critical(this, tr("Error exporting DDS"), + tr("Error: Could not open file %1 for writing").arg(filename), + QMessageBox::Ok); + return; + } - hsFileStream S; - if (!S.open(qstr2st(filename), fmCreate)) { - QMessageBox::critical(this, tr("Error exporting JPEG"), - tr("Error: Could not open file %1 for writing").arg(filename), - QMessageBox::Ok); - return; - } - if (tex->isImageJPEG()) - S.write(tex->getJpegSize(), tex->getJpegImage()); - else - makeJColorSurface(tex, &S); - S.close(); + try { + plDDSurface dds; + dds.setFromMipmap(tex); + dds.write(&S); - if (!S.open(qstr2st(alphaFname), fmCreate)) { - QMessageBox::critical(this, tr("Error exporting JPEG"), - tr("Error: Could not open file %1 for writing").arg(alphaFname), - QMessageBox::Ok); - return; + S.close(); + } catch (hsException& ex) { + QMessageBox::critical(this, tr("Error exporting DDS"), + QString::fromUtf8(ex.what()), QMessageBox::Ok); + } } - if (tex->isAlphaJPEG()) - S.write(tex->getJpegAlphaSize(), tex->getJpegAlpha()); - else - makeJAlphaSurface(tex, &S); - S.close(); - - setExportDir(filename); -} - -void QMipmap::onImportDDS() -{ - plMipmap* tex = plMipmap::Convert(fCreatable); - QString filename = QFileDialog::getOpenFileName(this, tr("Import DDS"), getExportDir(), - "DDS Files (*.dds)"); - if (filename.isEmpty()) - return; + else if (file_ext == "jpg" || file_ext == "jpeg") { + hsFileStream S; + if (!S.open(qstr2st(filename), fmCreate)) { + QMessageBox::critical(this, tr("Error exporting JPEG"), + tr("Error: Could not open file %1 for writing").arg(filename), + QMessageBox::Ok); + return; + } - hsFileStream S; - if (!S.open(qstr2st(filename), fmRead)) { - QMessageBox::critical(this, tr("Error importing DDS"), - tr("Error: Could not open file %1 for reading").arg(filename), - QMessageBox::Ok); - return; + if (tex->isImageJPEG()) { + S.write(tex->getJpegSize(), tex->getJpegImage()); + } else { + size_t image_size = tex->GetUncompressedSize(0); + auto image_data = new unsigned char[image_size]; + tex->DecompressImage(0, image_data, image_size); + plJPEG::CompressJPEG(&S, (void*)(image_data), image_size, tex->getWidth(), tex->getHeight(), tex->getBPP()); + delete[] image_data; + } + S.close(); } - try { - plDDSurface dds; - dds.read(&S); - plMipmap* newTex = dds.createMipmap(); - tex->CopyFrom(newTex); - delete newTex; - } catch (hsException& ex) { - QMessageBox::critical(this, tr("Error importing DDS"), - QString::fromUtf8(ex.what()), QMessageBox::Ok); + else if (file_ext == "png") { + hsFileStream S; + if (!S.open(qstr2st(filename), fmCreate)) { + QMessageBox::critical(this, tr("Error exporting PNG"), + tr("Error: Could not open file %1 for writing").arg(filename), + QMessageBox::Ok); + return; + } + + try { + auto imageData = getTextureData(tex); + plPNG::CompressPNG(&S, imageData, tex->GetUncompressedSize(0), tex->getLevelWidth(0), tex->getLevelHeight(0), tex->getBPP()); + } catch (hsException& ex) { + QMessageBox::critical(this, tr("Error exporting PNG"), + QString::fromUtf8(ex.what()), QMessageBox::Ok); + } + S.close(); } - S.close(); setExportDir(filename); } -void QMipmap::onImportJPEG() +void QMipmap::onImportImage() { - QString exportDir = getExportDir(); - + QString importDir = getExportDir(); plMipmap* tex = plMipmap::Convert(fCreatable); - QString filename = QFileDialog::getOpenFileName(this, tr("Import JPEG"), exportDir, - "JPEG Files (*.jpg *.jpeg *.dds)"); + + importDir.append("/" + st2qstr(tex->getKey()->getName()) + .replace(QRegularExpression("[?:/\\*\"<>|]"), "_")); + QString filter = tr("DDS Files (*.dds);;JPEG Files (*.jpg *.jpeg);;PNG Files (*.png)"); + QString filename = QFileDialog::getOpenFileName(this, tr("Import Image"), importDir, filter); + if (filename.isEmpty()) return; - QString alphaFname = QFileDialog::getOpenFileName(this, tr("Import JPEG Alpha"), exportDir, - "JPEG Files (*.jpg *.jpeg *.dds)"); - if (alphaFname.isEmpty()) - return; - plMipmap newTex; hsFileStream S; - bool valid = true; if (!S.open(qstr2st(filename), fmRead)) { - QMessageBox::critical(this, tr("Error importing JPEG"), - tr("Error: Could not open file %1 for reading").arg(filename), - QMessageBox::Ok); - valid = false; - } - if (filename.toLower().endsWith(".dds")) { - try { - plDDSurface dds; - dds.read(&S); - if (!getJColorSurface(dds, &newTex)) - valid = false; - } catch (hsException& ex) { - QMessageBox::critical(this, tr("Error importing JPEG"), - QString::fromUtf8(ex.what()), QMessageBox::Ok); - valid = false; - } - } else { - unsigned char* data = new unsigned char[S.size()]; - S.read(S.size(), data); - QImage imgTemp(filename); - newTex.Create(imgTemp.width(), imgTemp.height(), 0, plBitmap::kJPEGCompression, - plBitmap::kRGB8888); - newTex.setImageJPEG(data, S.size()); - delete[] data; + QMessageBox::critical(this, tr("Error importing image"), + tr("Error: Could not open file %1 for reading").arg(filename), + QMessageBox::Ok); + return; } - S.close(); - if (!S.open(qstr2st(alphaFname), fmRead)) { - QMessageBox::critical(this, tr("Error importing JPEG"), - tr("Error: Could not open file %1 for reading").arg(alphaFname), - QMessageBox::Ok); - valid = false; - } - if (alphaFname.toLower().endsWith(".dds")) { - try { + try { + QString file_ext = QFileInfo(filename).suffix(); + if (file_ext == "dds") { plDDSurface dds; dds.read(&S); - if (!getJAlphaSurface(dds, &newTex)) - valid = false; - } catch (hsException& ex) { - QMessageBox::critical(this, tr("Error importing JPEG"), - QString::fromUtf8(ex.what()), QMessageBox::Ok); - valid = false; + plMipmap* newTex = dds.createMipmap(); + tex->CopyFrom(newTex); + delete newTex; } - } else { - unsigned char* data = new unsigned char[S.size()]; - S.read(S.size(), data); - newTex.setAlphaJPEG(data, S.size()); - delete[] data; + else if (file_ext == "jpg" || file_ext == "jpeg") { + plMipmap* newTex = plJPEG::DecompressJPEG(&S); + tex->CopyFrom(newTex); + delete newTex; + } + else if (file_ext == "png") { + plMipmap* newTex = plPNG::DecompressPNG(&S); + tex->CopyFrom(newTex); + delete newTex; + } + } + catch (hsException& ex) { + QMessageBox::critical(this, tr("Error importing image"), + QString::fromUtf8(ex.what()), QMessageBox::Ok); } S.close(); - - if (valid) - tex->CopyFrom(&newTex); - - setExportDir(filename); } diff --git a/src/PrpShop/PRP/Surface/QMipmap.h b/src/PrpShop/PRP/Surface/QMipmap.h index b8fcf91..a4345fb 100644 --- a/src/PrpShop/PRP/Surface/QMipmap.h +++ b/src/PrpShop/PRP/Surface/QMipmap.h @@ -85,10 +85,8 @@ class QMipmap : public QCreatable QMipmap(plCreatable* pCre, QWidget* parent = NULL); private slots: - void onExportDDS(); - void onExportJPEG(); - void onImportDDS(); - void onImportJPEG(); + void onExportImage(); + void onImportImage(); }; QString getCompressionText(plBitmap* tex); From 9eb8df3a604eacab606e9511fef7157dba30c637 Mon Sep 17 00:00:00 2001 From: Joseph Davies Date: Sun, 23 Oct 2022 12:52:37 -0700 Subject: [PATCH 4/8] Remove deprecated DDS<->JPG conversion functions. --- src/PrpShop/PRP/Surface/QMipmap.cpp | 129 ---------------------------- 1 file changed, 129 deletions(-) diff --git a/src/PrpShop/PRP/Surface/QMipmap.cpp b/src/PrpShop/PRP/Surface/QMipmap.cpp index 785252a..a8bb857 100644 --- a/src/PrpShop/PRP/Surface/QMipmap.cpp +++ b/src/PrpShop/PRP/Surface/QMipmap.cpp @@ -342,135 +342,6 @@ QMipmap::QMipmap(plCreatable* pCre, QWidget* parent) connect(iPort, &QLinkLabel::activated, this, &QMipmap::onImportImage); } -static void swapColorChannels(unsigned char* data, size_t size) -{ - unsigned int* dp = reinterpret_cast(data); - for (size_t i=0; i> 16 - | (*dp & 0x000000FF) << 16; - dp++; - } -} - -static void makeJColorSurface(const plMipmap* tex, hsStream* S) -{ - if (tex->getCompressionType() != plBitmap::kJPEGCompression) { - QMessageBox::critical(NULL, QObject::tr("Error exporting JPEG"), - QObject::tr("Texture is not in a supported export format"), - QMessageBox::Ok); - return; - } - - plDDSurface dds; - dds.fFlags = plDDSurface::DDSD_CAPS | plDDSurface::DDSD_HEIGHT - | plDDSurface::DDSD_WIDTH | plDDSurface::DDSD_PIXELFORMAT - | plDDSurface::DDSD_LINEARSIZE; - dds.fCaps = plDDSurface::DDSCAPS_TEXTURE; - dds.fHeight = tex->getHeight(); - dds.fWidth = tex->getWidth(); - dds.fLinearSize = dds.fHeight * dds.fWidth * 3; - dds.fPixelFormat.fFlags = plDDSurface::DDPF_RGB; - dds.fPixelFormat.fBitDepth = 24; - dds.fPixelFormat.fRBitMask = 0xFF0000; - dds.fPixelFormat.fGBitMask = 0x00FF00; - dds.fPixelFormat.fBBitMask = 0x0000FF; - - // Strip down data to 24 bit color - unsigned char* data = new unsigned char[dds.fLinearSize]; - tex->extractColorData(data, dds.fLinearSize); - swapColorChannels(data, dds.fLinearSize); - dds.setData(dds.fLinearSize, data); - delete[] data; - - dds.write(S); -} - -static void makeJAlphaSurface(const plMipmap* tex, hsStream* S) -{ - if (tex->getCompressionType() != plBitmap::kJPEGCompression) { - QMessageBox::critical(NULL, QObject::tr("Error exporting JPEG"), - QObject::tr("Texture is not in a supported export format"), - QMessageBox::Ok); - return; - } - - plDDSurface dds; - dds.fFlags = plDDSurface::DDSD_CAPS | plDDSurface::DDSD_HEIGHT - | plDDSurface::DDSD_WIDTH | plDDSurface::DDSD_PIXELFORMAT - | plDDSurface::DDSD_LINEARSIZE; - dds.fCaps = plDDSurface::DDSCAPS_TEXTURE; - dds.fHeight = tex->getHeight(); - dds.fWidth = tex->getWidth(); - dds.fLinearSize = dds.fHeight * dds.fWidth; - dds.fPixelFormat.fFlags = plDDSurface::DDPF_LUMINANCE; - dds.fPixelFormat.fBitDepth = 8; - dds.fPixelFormat.fLuminanceBitMask = 0xFF; - - // Strip down data to alpha luminance - unsigned char* data = new unsigned char[dds.fLinearSize]; - tex->extractAlphaData(data, dds.fLinearSize); - dds.setData(dds.fLinearSize, data); - delete[] data; - - dds.write(S); -} - -static bool getJColorSurface(const plDDSurface& dds, plMipmap* tex) -{ - if ((dds.fFlags & plDDSurface::DDSD_HEIGHT) == 0 || - (dds.fFlags & plDDSurface::DDSD_WIDTH) == 0 || - (dds.fFlags & plDDSurface::DDSD_PIXELFORMAT) == 0) { - QMessageBox::critical(NULL, QObject::tr("Error importing JPEG"), - QObject::tr("DDSurface does not contain required fields"), - QMessageBox::Ok); - return false; - } - if ((dds.fPixelFormat.fFlags & plDDSurface::DDPF_RGB) == 0 || - (dds.fPixelFormat.fBitDepth != 24) || - (dds.fPixelFormat.fRBitMask != 0xFF0000) || - (dds.fPixelFormat.fGBitMask != 0x00FF00) || - (dds.fPixelFormat.fBBitMask != 0x0000FF)) { - QMessageBox::critical(NULL, QObject::tr("Error importing JPEG"), - QObject::tr("DDS file should be in RGB888 format")); - return false; - } - - tex->Create(dds.fWidth, dds.fHeight, 0, plBitmap::kJPEGCompression, plBitmap::kRGB8888); - tex->setColorData(dds.getData(), dds.getDataSize()); - swapColorChannels(reinterpret_cast(tex->getImageData()), dds.getDataSize()); - return true; -} - -static bool getJAlphaSurface(const plDDSurface& dds, plMipmap* tex) -{ - if ((dds.fFlags & plDDSurface::DDSD_HEIGHT) == 0 || - (dds.fFlags & plDDSurface::DDSD_WIDTH) == 0 || - (dds.fFlags & plDDSurface::DDSD_PIXELFORMAT) == 0) { - QMessageBox::critical(NULL, QObject::tr("Error importing JPEG"), - QObject::tr("DDSurface does not contain required fields"), - QMessageBox::Ok); - return false; - } - if ((dds.fPixelFormat.fFlags & plDDSurface::DDPF_LUMINANCE) == 0 || - (dds.fPixelFormat.fBitDepth != 8) || - (dds.fPixelFormat.fLuminanceBitMask != 0xFF)) { - QMessageBox::critical(NULL, QObject::tr("Error importing JPEG"), - QObject::tr("DDS file should be in Luminance 8-bit format"), - QMessageBox::Ok); - return false; - } - - if (tex->getWidth() != dds.fWidth || tex->getHeight() != dds.fHeight) { - QMessageBox::critical(NULL, QObject::tr("Error importing JPEG"), - QObject::tr("Alpha DDS size does not match image size"), - QMessageBox::Ok); - return false; - } - tex->setAlphaData(dds.getData(), dds.getDataSize()); - return true; -} - void QMipmap::onExportImage() { QString exportDir = getExportDir(); plMipmap* tex = plMipmap::Convert(fCreatable); From 51b46efa8d321f9d739a9af6db43757948b4266e Mon Sep 17 00:00:00 2001 From: Joseph Davies Date: Wed, 6 Mar 2024 10:36:20 -0800 Subject: [PATCH 5/8] Default to all supported image formats for import filter. --- src/PrpShop/PRP/Surface/QMipmap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PrpShop/PRP/Surface/QMipmap.cpp b/src/PrpShop/PRP/Surface/QMipmap.cpp index a8bb857..ff90363 100644 --- a/src/PrpShop/PRP/Surface/QMipmap.cpp +++ b/src/PrpShop/PRP/Surface/QMipmap.cpp @@ -424,7 +424,7 @@ void QMipmap::onImportImage() importDir.append("/" + st2qstr(tex->getKey()->getName()) .replace(QRegularExpression("[?:/\\*\"<>|]"), "_")); - QString filter = tr("DDS Files (*.dds);;JPEG Files (*.jpg *.jpeg);;PNG Files (*.png)"); + QString filter = tr("All Images (*.dds *.jpg *.jpeg *.png);;DDS Files (*.dds);;JPEG Files (*.jpg *.jpeg);;PNG Files (*.png)"); QString filename = QFileDialog::getOpenFileName(this, tr("Import Image"), importDir, filter); if (filename.isEmpty()) From dd756fdd866e3df8b30ad157dcfa40ae843487d4 Mon Sep 17 00:00:00 2001 From: Joseph Davies Date: Sat, 9 Mar 2024 15:19:41 -0800 Subject: [PATCH 6/8] Consolidate byte-swapping for color components. Co-authored-by: Michael Hansen --- src/PrpShop/PRP/Surface/QMipmap.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/PrpShop/PRP/Surface/QMipmap.cpp b/src/PrpShop/PRP/Surface/QMipmap.cpp index ff90363..a75d32b 100644 --- a/src/PrpShop/PRP/Surface/QMipmap.cpp +++ b/src/PrpShop/PRP/Surface/QMipmap.cpp @@ -66,9 +66,8 @@ unsigned char* getTextureData(plMipmap *tex, size_t level=0) unsigned int* dp = (unsigned int*)imageData; for (size_t i = 0; i < size; i += 4) { //unsigned int alpha = doAlpha ? (*dp & 0xFF000000) : 0xFF000000; - *dp = (*dp & 0xFF000000) + *dp = (*dp & 0xFF00FF00) | (*dp & 0x00FF0000) >> 16 - | (*dp & 0x0000FF00) | (*dp & 0x000000FF) << 16; dp++; } From 6cffc756729f5d38d92a83510529a56b1de5a44d Mon Sep 17 00:00:00 2001 From: Joseph Davies Date: Tue, 12 Nov 2024 05:38:48 -0800 Subject: [PATCH 7/8] Add cleanup suggestions from code review. --- src/PrpShop/PRP/Surface/QMipmap.cpp | 48 ++++++++++------------------- 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/src/PrpShop/PRP/Surface/QMipmap.cpp b/src/PrpShop/PRP/Surface/QMipmap.cpp index a75d32b..dc13d0e 100644 --- a/src/PrpShop/PRP/Surface/QMipmap.cpp +++ b/src/PrpShop/PRP/Surface/QMipmap.cpp @@ -52,13 +52,11 @@ static void setExportDir(const QString& filename) unsigned char* getTextureData(plMipmap *tex, size_t level=0) { - unsigned char *imageData; - if (level >= tex->getNumLevels()) level = tex->getNumLevels() - 1; size_t size = tex->GetUncompressedSize(level); - imageData = new unsigned char[size]; + unsigned char* imageData = new unsigned char[size]; tex->DecompressImage(level, imageData, size); if (tex->getCompressionType() == plMipmap::kDirectXCompression) { @@ -353,7 +351,7 @@ void QMipmap::onExportImage() { if (filename.isEmpty()) return; - QString file_ext = QFileInfo(filename).suffix(); + QString file_ext = QFileInfo(filename).suffix().toLower(); if (file_ext == "dds") { hsFileStream S; if (!S.open(qstr2st(filename), fmCreate)) { @@ -373,8 +371,7 @@ void QMipmap::onExportImage() { QMessageBox::critical(this, tr("Error exporting DDS"), QString::fromUtf8(ex.what()), QMessageBox::Ok); } - } - else if (file_ext == "jpg" || file_ext == "jpeg") { + } else if (file_ext == "jpg" || file_ext == "jpeg") { hsFileStream S; if (!S.open(qstr2st(filename), fmCreate)) { QMessageBox::critical(this, tr("Error exporting JPEG"), @@ -387,14 +384,11 @@ void QMipmap::onExportImage() { S.write(tex->getJpegSize(), tex->getJpegImage()); } else { size_t image_size = tex->GetUncompressedSize(0); - auto image_data = new unsigned char[image_size]; - tex->DecompressImage(0, image_data, image_size); - plJPEG::CompressJPEG(&S, (void*)(image_data), image_size, tex->getWidth(), tex->getHeight(), tex->getBPP()); - delete[] image_data; + auto image_data = std::make_unique(image_size); + tex->DecompressImage(0, image_data.get(), image_size); + plJPEG::CompressJPEG(&S, image_data.get(), image_size, tex->getWidth(), tex->getHeight(), tex->getBPP()); } - S.close(); - } - else if (file_ext == "png") { + } else if (file_ext == "png") { hsFileStream S; if (!S.open(qstr2st(filename), fmCreate)) { QMessageBox::critical(this, tr("Error exporting PNG"), @@ -410,7 +404,6 @@ void QMipmap::onExportImage() { QMessageBox::critical(this, tr("Error exporting PNG"), QString::fromUtf8(ex.what()), QMessageBox::Ok); } - S.close(); } setExportDir(filename); @@ -438,28 +431,21 @@ void QMipmap::onImportImage() } try { - QString file_ext = QFileInfo(filename).suffix(); + QString file_ext = QFileInfo(filename).suffix().toLower(); if (file_ext == "dds") { plDDSurface dds; dds.read(&S); - plMipmap* newTex = dds.createMipmap(); - tex->CopyFrom(newTex); - delete newTex; + std::unique_ptr newTex(dds.createMipmap()); + tex->CopyFrom(newTex.get()); + } else if (file_ext == "jpg" || file_ext == "jpeg") { + std::unique_ptr newTex(plJPEG::DecompressJPEG(&S)); + tex->CopyFrom(newTex.get()); + } else if (file_ext == "png") { + std::unique_ptr newTex(plPNG::DecompressPNG(&S)); + tex->CopyFrom(newTex.get()); } - else if (file_ext == "jpg" || file_ext == "jpeg") { - plMipmap* newTex = plJPEG::DecompressJPEG(&S); - tex->CopyFrom(newTex); - delete newTex; - } - else if (file_ext == "png") { - plMipmap* newTex = plPNG::DecompressPNG(&S); - tex->CopyFrom(newTex); - delete newTex; - } - } - catch (hsException& ex) { + } catch (hsException& ex) { QMessageBox::critical(this, tr("Error importing image"), QString::fromUtf8(ex.what()), QMessageBox::Ok); } - S.close(); } From 3e476d394660468e5fe79462fb9c64def33c83fe Mon Sep 17 00:00:00 2001 From: Joseph Davies Date: Mon, 10 Feb 2025 11:50:02 -0800 Subject: [PATCH 8/8] Use unique_ptr to prevent image data leak. --- src/PrpShop/PRP/Surface/QMipmap.cpp | 14 ++++++-------- src/PrpShop/PRP/Surface/QMipmap.h | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/PrpShop/PRP/Surface/QMipmap.cpp b/src/PrpShop/PRP/Surface/QMipmap.cpp index dc13d0e..ed5284a 100644 --- a/src/PrpShop/PRP/Surface/QMipmap.cpp +++ b/src/PrpShop/PRP/Surface/QMipmap.cpp @@ -50,18 +50,18 @@ static void setExportDir(const QString& filename) settings.setValue("ExportDir", dir.absolutePath()); } -unsigned char* getTextureData(plMipmap *tex, size_t level=0) +std::unique_ptr getTextureData(plMipmap *tex, size_t level=0) { if (level >= tex->getNumLevels()) level = tex->getNumLevels() - 1; size_t size = tex->GetUncompressedSize(level); - unsigned char* imageData = new unsigned char[size]; - tex->DecompressImage(level, imageData, size); + auto imageData = std::unique_ptr{ new unsigned char[size] }; + tex->DecompressImage(level, imageData.get(), size); if (tex->getCompressionType() == plMipmap::kDirectXCompression) { // Manipulate the data from RGBA to BGRA - unsigned int* dp = (unsigned int*)imageData; + unsigned int* dp = (unsigned int*)imageData.get(); for (size_t i = 0; i < size; i += 4) { //unsigned int alpha = doAlpha ? (*dp & 0xFF000000) : 0xFF000000; *dp = (*dp & 0xFF00FF00) @@ -78,13 +78,11 @@ unsigned char* getTextureData(plMipmap *tex, size_t level=0) QTextureBox::~QTextureBox() { delete fImage; - delete[] fImageData; } void QTextureBox::setTexture(plMipmap* tex, int level) { delete fImage; - delete[] fImageData; if (tex == NULL) { fImage = NULL; @@ -103,7 +101,7 @@ void QTextureBox::setTexture(plMipmap* tex, int level) } fImageData = getTextureData(tex, level); - fImage = new QImage(fImageData, tex->getLevelWidth(level), + fImage = new QImage(fImageData.get(), tex->getLevelWidth(level), tex->getLevelHeight(level), QImage::Format_ARGB32); resize(tex->getLevelWidth(level), tex->getLevelHeight(level)); update(); @@ -399,7 +397,7 @@ void QMipmap::onExportImage() { try { auto imageData = getTextureData(tex); - plPNG::CompressPNG(&S, imageData, tex->GetUncompressedSize(0), tex->getLevelWidth(0), tex->getLevelHeight(0), tex->getBPP()); + plPNG::CompressPNG(&S, imageData.get(), tex->GetUncompressedSize(0), tex->getLevelWidth(0), tex->getLevelHeight(0), tex->getBPP()); } catch (hsException& ex) { QMessageBox::critical(this, tr("Error exporting PNG"), QString::fromUtf8(ex.what()), QMessageBox::Ok); diff --git a/src/PrpShop/PRP/Surface/QMipmap.h b/src/PrpShop/PRP/Surface/QMipmap.h index a4345fb..b69eece 100644 --- a/src/PrpShop/PRP/Surface/QMipmap.h +++ b/src/PrpShop/PRP/Surface/QMipmap.h @@ -30,7 +30,7 @@ class QTextureBox : public QWidget protected: QImage* fImage; - unsigned char* fImageData; + std::unique_ptr fImageData; public: QTextureBox(QWidget* parent = NULL)