Skip to content

Commit eedc422

Browse files
committed
RecompressIfTooBig/FileSizeThresholdToRecompress, CalcCRC32 with bugfixes, MakeUniqueFilename bugfixes, ConvertToJPG bugfixes
1 parent fbf01a8 commit eedc422

File tree

2 files changed

+121
-28
lines changed

2 files changed

+121
-28
lines changed

include/DzBridgeAction.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,13 @@ namespace DzBridgeNameSpace
123123
Q_INVOKABLE virtual void setNumberOfLods(int arg) { m_nNumberOfLods = arg; }
124124

125125
Q_INVOKABLE virtual DzNode* getSelectedNode() { return m_pSelectedNode; }
126+
Q_INVOKABLE virtual unsigned int calcCRC32(QString sFilename);
127+
Q_INVOKABLE virtual int getCalcCRC32ResultCode() { return (int) m_nCalcCRC32ResultCode; }
128+
enum CalcCRC32ResultCodes
129+
{
130+
SUCCESS = 0,
131+
ERROR_OPENING_FILE = -1,
132+
} m_nCalcCRC32ResultCode = CalcCRC32ResultCodes::SUCCESS;
126133

127134
QList<LodInfo*> m_aLodInfo;
128135

@@ -208,6 +215,8 @@ namespace DzBridgeNameSpace
208215
bool m_bResizeTextures = false;
209216
QSize m_qTargetTextureSize = QSize(4096, 4096);
210217
bool m_bMultiplyTextureValues = false;
218+
bool m_bRecompressIfFileSizeTooBig = false;
219+
int m_nFileSizeThresholdToInitiateRecompression = 1024*1024*10; // size in bytes
211220

212221
virtual QString getActionGroup() const { return tr("Bridges"); }
213222
virtual QString getDefaultMenuPath() const { return tr("&File/Send To"); }
@@ -310,7 +319,7 @@ namespace DzBridgeNameSpace
310319
virtual QString exportAssetWithDtu(QString sFilename, QString sAssetMaterialName = "");
311320
virtual void writePropertyTexture(DzJsonWriter& Writer, QString sName, QString sLabel, QString sValue, QString sType, QString sTexture);
312321
virtual void writePropertyTexture(DzJsonWriter& Writer, QString sName, QString sLabel, double dValue, QString sType, QString sTexture);
313-
virtual QString makeUniqueFilename(QString sFilename);
322+
virtual QString makeUniqueFilename(QString sTargetFilename, QString sOriginalFilename="");
314323

315324
Q_INVOKABLE bool getGenerateNormalMaps() { return this->m_bGenerateNormalMaps; };
316325
Q_INVOKABLE void setGenerateNormalMaps(bool arg_GenerateNormalMaps) { this->m_bGenerateNormalMaps = arg_GenerateNormalMaps; };

src/DzBridgeAction.cpp

Lines changed: 111 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@
6565
#include <qimage.h>
6666
#include "ImageTools.h"
6767

68+
// miniz-lib
69+
extern "C"
70+
{
71+
unsigned long mz_crc32(unsigned long crc, const unsigned char* ptr, size_t buf_len);
72+
}
73+
6874
using namespace DzBridgeNameSpace;
6975

7076
/// <summary>
@@ -2375,10 +2381,13 @@ QString DzBridgeAction::exportAssetWithDtu(QString sFilename, QString sAssetMate
23752381

23762382
QString exportPath = this->m_sRootFolder.replace("\\","/") + "/" + this->m_sExportSubfolder.replace("\\", "/");
23772383
QString fileStem = QFileInfo(sFilename).fileName();
2378-
// DB 2023-Oct-20: FIX for non-unique filenames
2379-
if (isTemporaryFile(sFilename) == false)
2384+
// DB 2023-Oct-20: add partial path for short filenames
2385+
QString sNameTest = QFileInfo(sFilename).baseName().remove(QRegExp("[^A-Za-z]")).remove("base").remove("color").remove("normal").remove("roughness").remove("metallic").remove("height").remove("opengl");
2386+
if (isTemporaryFile(sFilename) == false &&
2387+
sNameTest.length() < 3 &&
2388+
QFileInfo(sFilename).baseName().length() < 20)
23802389
{
2381-
QStringList filePathArray = cleanedFilename.replace(" ", "").split("/");
2390+
QStringList filePathArray = cleanedFilename.remove(" ").split("/");
23822391
int len = filePathArray.count();
23832392
for (int i = 2; i < 5; i++)
23842393
{
@@ -2392,7 +2401,7 @@ QString DzBridgeAction::exportAssetWithDtu(QString sFilename, QString sAssetMate
23922401
// QString exportFilename = exportPath + cleanedAssetMaterialName + "_" + fileStem;
23932402
QString exportFilename = exportPath + fileStem;
23942403

2395-
exportFilename = makeUniqueFilename(exportFilename);
2404+
exportFilename = makeUniqueFilename(exportFilename, sFilename);
23962405

23972406
if (QFile(sFilename).copy(exportFilename) == true)
23982407
{
@@ -2401,33 +2410,80 @@ QString DzBridgeAction::exportAssetWithDtu(QString sFilename, QString sAssetMate
24012410

24022411
// copy method may fail if file already exists,
24032412
// if exists and same file size, then proceed as if successful
2413+
ulong crc32_Source = calcCRC32(sFilename);
2414+
int bFirstCRCResult = getCalcCRC32ResultCode();
2415+
if (bFirstCRCResult != CalcCRC32ResultCodes::SUCCESS)
2416+
{
2417+
dzApp->log("ERROR: exportAssetWithDTU(): CalcCRC32 was not successful for: " + sFilename);
2418+
}
2419+
ulong crc32_Dest = calcCRC32(exportFilename);
2420+
int bSecondCRCResult = getCalcCRC32ResultCode();
2421+
if (bSecondCRCResult != CalcCRC32ResultCodes::SUCCESS)
2422+
{
2423+
dzApp->log("ERROR: exportAssetWithDTU(): CalcCRC32 was not successful for: " + exportFilename);
2424+
}
24042425
if ( QFileInfo(exportFilename).exists() &&
2405-
QFileInfo(sFilename).size() == QFileInfo(exportFilename).size())
2426+
QFileInfo(sFilename).size() == QFileInfo(exportFilename).size() &&
2427+
bFirstCRCResult == CalcCRC32ResultCodes::SUCCESS &&
2428+
bSecondCRCResult == CalcCRC32ResultCodes::SUCCESS &&
2429+
crc32_Source == crc32_Dest )
24062430
{
24072431
return exportFilename;
24082432
}
24092433

24102434
// return original source string if failed
2435+
dzApp->log("ERROR: exportAssetWithDTU(): Unexpected error occured while preparing file: " + sFilename);
24112436
return sFilename;
24122437

24132438
}
24142439

2440+
unsigned int DzBridgeAction::calcCRC32(QString sFilename)
2441+
{
2442+
ulong crc32Result = 0;
2443+
m_nCalcCRC32ResultCode = CalcCRC32ResultCodes::SUCCESS;
2444+
2445+
QFile oFile(sFilename);
2446+
if (oFile.open(QIODevice::OpenModeFlag::ReadOnly) == false)
2447+
{
2448+
m_nCalcCRC32ResultCode = CalcCRC32ResultCodes::ERROR_OPENING_FILE;
2449+
return 0;
2450+
}
2451+
2452+
QByteArray byteArray = oFile.readAll();
2453+
crc32Result = (ulong) ::mz_crc32((ulong)crc32Result, (const unsigned char*) byteArray.constData(), byteArray.size());
2454+
2455+
oFile.close();
2456+
2457+
return crc32Result;
2458+
}
2459+
24152460
// TODO: This method will fail because uncompressed textures of the same dimension
24162461
// will have the same file size. Instead, must use a file content hash function.
2417-
QString DzBridgeAction::makeUniqueFilename(QString sFilename)
2462+
QString DzBridgeAction::makeUniqueFilename(QString sTargetFilename, QString sOriginalFilename)
24182463
{
2419-
if (QFileInfo(sFilename).exists() != true)
2420-
return sFilename;
2464+
if (QFileInfo(sTargetFilename).exists() != true)
2465+
return sTargetFilename;
24212466

2422-
QString newFilename = sFilename;
2423-
int duplicate_count = 0;
2467+
QString newFilename = sTargetFilename;
2468+
int duplicate_count = 0;
24242469

2425-
while (
2426-
QFileInfo(newFilename).exists() &&
2427-
QFileInfo(sFilename).size() != QFileInfo(newFilename).size()
2428-
)
2470+
while (QFileInfo(newFilename).exists())
24292471
{
2430-
newFilename = sFilename + QString("_%i").arg(duplicate_count++);
2472+
if (sOriginalFilename != "")
2473+
{
2474+
if ( QFileInfo(sOriginalFilename).size() == QFileInfo(newFilename).size() &&
2475+
calcCRC32(sOriginalFilename) == calcCRC32(newFilename) )
2476+
{
2477+
// OK to use as unique, because original and new file are equivalent (per CRC32)
2478+
// TODO: replace with MD5 or SHA to reduce frequency of false positive
2479+
break;
2480+
}
2481+
}
2482+
QFileInfo fileInfo(sTargetFilename);
2483+
QString sExt = fileInfo.suffix();
2484+
QString sNameWtihoutExt = fileInfo.completeBaseName();
2485+
QString sPath = fileInfo.path();
2486+
newFilename = sPath + "/" + sNameWtihoutExt + QString("_%1").arg(duplicate_count++) + "." + sExt;
24312487
}
24322488

24332489
return newFilename;
@@ -2674,31 +2730,59 @@ void DzBridgeAction::writeMaterialProperty(DzNode* Node, DzJsonWriter& Writer, Q
26742730
}
26752731

26762732
QString dtuTextureName = TextureName;
2677-
if (TextureName != "")
2733+
if (TextureName != "" || TextureName.count() != 0)
26782734
{
2679-
// DB 2023-Oct-5: Save to PNG, Export all Textures
2680-
if (m_bConvertToPng || m_bConvertToJpg)
2735+
// DB 2023-Oct-23: Recompress if filesize too big
2736+
if (m_bRecompressIfFileSizeTooBig)
26812737
{
2682-
if ( m_bConvertToJpg ||
2683-
TextureName.endsWith(".png", Qt::CaseInsensitive) == false &&
2684-
TextureName.endsWith(".jpg", Qt::CaseInsensitive) == false &&
2685-
TextureName.endsWith(".jpeg", Qt::CaseInsensitive) == false)
2738+
// only re-compress to jpeg if file is large
2739+
if (QFileInfo(TextureName).size() > m_nFileSizeThresholdToInitiateRecompression)
26862740
{
26872741
// load image and resave as PNG
26882742
DzImageMgr* imageMgr = dzApp->getImageMgr();
26892743
QImage image = imageMgr->loadImage(TextureName);
26902744
QString cleanedTempPath = dzApp->getTempPath().toLower().replace("\\", "/");
26912745
QString filestem = QFileInfo(TextureName).fileName();
2692-
QString pngFilename = cleanedTempPath + "/" + filestem + ".png";
2693-
if (m_bConvertToJpg)
2746+
QString recompressedFilename;
2747+
QString fileTypeExtension = ".jpg";
2748+
if (!m_bConvertToJpg && m_bConvertToPng) // default to jpg, unless png=true and jpg=false
2749+
fileTypeExtension = ".png";
2750+
recompressedFilename = cleanedTempPath + "/" + filestem + fileTypeExtension;
2751+
if (fileTypeExtension == ".png")
26942752
{
2695-
pngFilename = cleanedTempPath + "/" + filestem + ".jpg";
2696-
image.save(pngFilename, "jpg", 95);
2753+
if (image.save(recompressedFilename, "png", 95) == false) // 95% quality
2754+
{
2755+
dzApp->log("ERROR: saving file failed: " + recompressedFilename);
2756+
}
26972757
}
26982758
else
26992759
{
2700-
imageMgr->saveImage(pngFilename, image);
2760+
if (image.save(recompressedFilename, "jpg", 95) == false) // 95% quality
2761+
{
2762+
dzApp->log("ERROR: saving file failed: " + recompressedFilename);
2763+
}
2764+
27012765
}
2766+
dtuTextureName = TextureName = recompressedFilename;
2767+
}
2768+
}
2769+
// DB 2023-Oct-5: Save to PNG or JPG, Export all Textures
2770+
if (m_bConvertToPng || m_bConvertToJpg)
2771+
{
2772+
if (TextureName.endsWith(".png", Qt::CaseInsensitive) == false &&
2773+
TextureName.endsWith(".jpg", Qt::CaseInsensitive) == false &&
2774+
TextureName.endsWith(".jpeg", Qt::CaseInsensitive) == false)
2775+
{
2776+
// load image and resave as PNG
2777+
DzImageMgr* imageMgr = dzApp->getImageMgr();
2778+
QImage image = imageMgr->loadImage(TextureName);
2779+
QString cleanedTempPath = dzApp->getTempPath().toLower().replace("\\", "/");
2780+
QString filestem = QFileInfo(TextureName).fileName();
2781+
QString fileTypeExtension = ".png";
2782+
if (m_bConvertToJpg) // jpg conversion takes priority over png
2783+
fileTypeExtension = ".jpg";
2784+
QString pngFilename = cleanedTempPath + "/" + filestem + fileTypeExtension;
2785+
imageMgr->saveImage(pngFilename, image);
27022786
dtuTextureName = TextureName = pngFilename;
27032787
}
27042788
}

0 commit comments

Comments
 (0)