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+
6874using 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