diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e5ddfe..5f2b364 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,7 @@ set(CMAKE_AUTOMOC ON) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt6 6.2 REQUIRED COMPONENTS Quick QuickControls2) +find_package(PNG REQUIRED) qt_add_executable(apptexcrafting @@ -19,6 +20,7 @@ qt_add_qml_module(apptexcrafting Main.qml TexSlot.qml SOURCES texturecrafter.h texturecrafter.cpp + RESOURCES ) # Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. @@ -34,6 +36,7 @@ set_target_properties(apptexcrafting PROPERTIES target_link_libraries(apptexcrafting PRIVATE Qt6::Quick + PNG::PNG ) include(GNUInstallDirs) diff --git a/texturecrafter.cpp b/texturecrafter.cpp index 4e2880c..50b7ca2 100644 --- a/texturecrafter.cpp +++ b/texturecrafter.cpp @@ -4,6 +4,18 @@ TextureCrafter::TextureCrafter(QObject *parent) : QObject{parent} {} +QString TextureCrafter::getOutFilename() { + QString outFileName; + if (outDir.isValid()) { + outFileName = outDir.path(); + outFileName.append("/out.png"); + } else { + return QString(); + } + + return outFileName; +} + QUrl TextureCrafter::packChannels(QVector imagePaths) { QVector sourceImages; @@ -26,43 +38,83 @@ QUrl TextureCrafter::packChannels(QVector imagePaths) { sourceImages.append(newImage); } - QImage outImage(width, height, format); + png_structp outPng; + png_infop outInfo; + FILE *outFile; + QString outFilename = getOutFilename(); + unsigned char *rowBuffer; + + // maybe abstract this? + outFile = fopen(outFilename.toLatin1().data(), "wb"); + + if (!outFile) { + return QUrl(); + } + + outPng = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + outInfo = png_create_info_struct(outPng); + rowBuffer = (unsigned char*)malloc(sizeof(char) * 3 * width); + + png_init_io(outPng, outFile); + + png_set_IHDR (outPng, + outInfo, + width, + height, + 8, // TODO: support other bit depths someday + PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + png_write_info(outPng, outInfo); // do the channel packing!! // theres probably a faster way to do this but eh - for (int i = 0; i < width; i++) { - for (int j = 0; j < height; j++) { - int r, g, b; + for (int i = 0; i < height; i++) { + memset(rowBuffer, 0, sizeof(char) * 3 * width); + for (int j = 0; j < width; j++) { + unsigned char r, g, b; // too eepy for dry - r = sourceImages.at(0).pixelColor(i, j).red(); - g = sourceImages.at(1).pixelColor(i, j).green(); - b = sourceImages.at(2).pixelColor(i, j).blue(); + r = sourceImages.at(0).pixelColor(j, i).red(); + g = sourceImages.at(1).pixelColor(j, i).green(); + b = sourceImages.at(2).pixelColor(j, i).blue(); - QColor newColor(r, g, b); - - outImage.setPixelColor(i, j, newColor); + rowBuffer[j*3+0] = r; + rowBuffer[j*3+1] = g; + rowBuffer[j*3+2] = b; } + + png_write_row(outPng, rowBuffer); } - // write it to a temp file - if (outDir.isValid()) { - QString outFileName = outDir.path(); - outFileName.append("/out.png"); + png_write_end(outPng, NULL); - printf("wrote to %s\n", outFileName.toLatin1().data()); + // good soldiers free their memory + free(rowBuffer); + png_destroy_write_struct(&outPng, &outInfo); + fclose(outFile); + return QUrl::fromLocalFile(outFilename); - //TODO: use libpng and do progressive write to update the progress bar - if (outImage.save(outFileName)) { - printf("cool ^-^\n"); - return QUrl::fromLocalFile(outFileName); - } else { - //TODO: return some error value to show the user - printf("that dream is fucked it is fucking fucked\n"); - } - } else { - printf("chat its so over\n"); - } + // // write it to a temp file + // if (outDir.isValid()) { + // QString outFileName = outDir.path(); + // outFileName.append("/out.png"); + + // printf("wrote to %s\n", outFileName.toLatin1().data()); + + // //TODO: use libpng and do progressive write to update the progress bar + // if (outImage.save(outFileName)) { + // printf("cool ^-^\n"); + // return QUrl::fromLocalFile(outFileName); + // } else { + // //TODO: return some error value to show the user + // printf("that dream is fucked it is fucking fucked\n"); + // } + // } else { + // printf("chat its so over\n"); + // } return QUrl(); //do we need to close these??? idk lets hope qt handles it diff --git a/texturecrafter.h b/texturecrafter.h index 4eccda2..3a5c124 100644 --- a/texturecrafter.h +++ b/texturecrafter.h @@ -6,6 +6,8 @@ #include #include +#include + class TextureCrafter : public QObject { Q_OBJECT @@ -17,6 +19,8 @@ public: signals: private: + QString getOutFilename(); + QTemporaryDir outDir; };