diff --git a/CMakeLists.txt b/CMakeLists.txt index bfc6a90..c3b002e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) include(GNUInstallDirs) -find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets Svg Xml PrintSupport TextToSpeech OpenGL OpenGLWidgets Multimedia Network Test 3dcore 3drender 3dinput 3dlogic 3dextras) +find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets Svg Xml PrintSupport TextToSpeech OpenGL OpenGLWidgets Multimedia Network Test 3dcore 3drender 3dinput 3dlogic 3dextras ShaderTools) qt_standard_project_setup() find_package(OpenSSL REQUIRED) diff --git a/Pdf4QtLib/sources/pdf3d_u3d.cpp b/Pdf4QtLib/sources/pdf3d_u3d.cpp index 543c932..605c3ef 100644 --- a/Pdf4QtLib/sources/pdf3d_u3d.cpp +++ b/Pdf4QtLib/sources/pdf3d_u3d.cpp @@ -16,6 +16,7 @@ // along with PDF4QT. If not, see . #include "pdf3d_u3d.h" +#include "pdfstreamfilters.h" #include #include @@ -915,6 +916,16 @@ private: float m_reserved3 = 0.0; }; +class PDF3D_U3D_RHAdobeMeshResourceBlock : public PDF3D_U3D_AbstractBlock +{ +public: + virtual EBlockType getBlockType() const override { return PDF3D_U3D_Block_Info::BT_Unknown; } + + static PDF3D_U3D_AbstractBlockPtr parse(QByteArray data, QByteArray metaData, PDF3D_U3D_Parser* object); + +private: +}; + class PDF3D_U3D_LineSetContinuationBlock : public PDF3D_U3D_AbstractBlock { public: @@ -1509,6 +1520,8 @@ public: void addBlockToU3D(PDF3D_U3D_AbstractBlockPtr block); + PDF3D_U3D_Block_Info::EPalette getPaletteByBlockType(uint32_t blockType) const; + QStringList getErrors() const { return m_errors; } private: @@ -1532,6 +1545,7 @@ private: bool m_isCompressed = true; uint32_t m_priority = 0; QStringDecoder m_stringDecoder; + uint32_t m_RHAdobeMeshResourceId = 0; }; class PDF3D_U3D_DataReader @@ -1547,6 +1561,7 @@ public: uint8_t readU8(); uint16_t readU16(); + uint32_t readU24(); uint32_t readU32(); uint64_t readU64(); int16_t readI16(); @@ -1672,6 +1687,14 @@ uint16_t PDF3D_U3D_DataReader::readU16() return low + (high << 8); } +uint32_t PDF3D_U3D_DataReader::readU24() +{ + const uint32_t low = readU8(); + const uint32_t high = readU8(); + const uint32_t highest = readU8(); + return low + (high << 8) + (highest << 16); +} + uint32_t PDF3D_U3D_DataReader::readU32() { const uint32_t low = readU16(); @@ -3416,6 +3439,16 @@ void PDF3D_U3D_Parser::addBlockToU3D(PDF3D_U3D_AbstractBlockPtr block) } } +PDF3D_U3D_Block_Info::EPalette PDF3D_U3D_Parser::getPaletteByBlockType(uint32_t blockType) const +{ + if (blockType == m_RHAdobeMeshResourceId) + { + return PDF3D_U3D_Block_Info::PL_Generator; + } + + return PDF3D_U3D_Block_Info::getPalette(static_cast(blockType)); +} + PDF3D_U3D_Parser::PDF3D_U3D_Parser() { // Jakub Melka: Utf-8 (MIB 106) is default value for U3D strings @@ -3503,6 +3536,19 @@ void PDF3D_U3D_Parser::processBlock(const PDF3D_U3D_Block_Data& blockData, } case PDF3D_U3D_NewObjectTypeBlock::ID: + { + auto block = parseBlock(blockData); + const PDF3D_U3D_NewObjectTypeBlock* newObjectTypeBlock = dynamic_cast(block.get()); + + // Right Hemisphere Adobe Mesh (RHAdobeMeshResource) + // {00000000-0000-0000-0000-000000000000} + if (newObjectTypeBlock->getExtensionId() == QUuid::fromString("{96a804a6-3fb9-43c5-b2df-2a31b5569340}")) + { + m_RHAdobeMeshResourceId = newObjectTypeBlock->getNewDeclarationBlockType(); + } + break; + } + case PDF3D_U3D_FileReferenceBlock::ID: // Skip this block, we do not handle these type of blocks, // just read it... to check errors. @@ -3558,7 +3604,7 @@ void PDF3D_U3D_Parser::processGenericBlock(const PDF3D_U3D_Block_Data& blockData uint32_t chainIndex = 0; PDF3D_U3D_Block_Info::EPalette effectivePalette = PDF3D_U3D_Block_Info::isChain(blockData.blockType) ? palette - : PDF3D_U3D_Block_Info::getPalette(blockData.blockType); + : getPaletteByBlockType(blockData.blockType); if (effectivePalette == PDF3D_U3D_Block_Info::PL_LastPalette) { @@ -3700,6 +3746,11 @@ PDF3D_U3D_AbstractBlockPtr PDF3D_U3D_Parser::parseBlock(uint32_t blockType, return PDF3D_U3D_MotionResourceBlock::parse(data, metaData, this); default: + if (blockType == m_RHAdobeMeshResourceId) + { + return PDF3D_U3D_RHAdobeMeshResourceBlock::parse(data, metaData, this); + } + m_errors << PDFTranslationContext::tr("Unable to parse block of type '%1'.").arg(blockType, 8, 16); break; } @@ -6766,6 +6817,154 @@ void PDF3D_U3D_Geometry::setShaders(const std::vector& newShaders) m_shaders = newShaders; } +PDF3D_U3D_AbstractBlockPtr PDF3D_U3D_RHAdobeMeshResourceBlock::parse(QByteArray data, QByteArray metaData, PDF3D_U3D_Parser* object) +{ + PDF3D_U3D_RHAdobeMeshResourceBlock* block = new PDF3D_U3D_RHAdobeMeshResourceBlock(); + PDF3D_U3D_AbstractBlockPtr pointer(block); + + PDF3D_U3D_DataReader reader(data, object->isCompressed()); + + QString objectName = reader.readString(object->getStringDecoder()); + uint32_t chainIndex = reader.readU32(); +/* + QByteArray remainingData = reader.readRemainingData(); + QByteArray uncompressedData = PDFFlateDecodeFilter::uncompress(remainingData); + return pointer; +*/ + // Read the data + while (!reader.isAtEnd()) + { + // Read the header + QString encoding = reader.readString(object->getStringDecoder()); + uint8_t flags = reader.readU8(); + + const bool hasExtensionData = flags & 0x10; + const bool hasSkeletonData = flags & 0x20; + const uint8_t materialTypeCount = flags >> 6; + + if (hasExtensionData) + { + uint32_t sizeOfTheMeshDescriptionBlock = reader.readU32(); + uint16_t numberOfSubChunks = reader.readU16(); + + Q_UNUSED(sizeOfTheMeshDescriptionBlock); + + for (uint16_t i = 0; i < numberOfSubChunks; ++i) + { + uint32_t subChunkSize = reader.readU32(); + uint16_t subChunkTypeInfo = reader.readU16(); + + Q_UNUSED(subChunkSize); + Q_UNUSED(subChunkTypeInfo); + } + } + + uint32_t materialCount = 0; + switch (materialTypeCount) + { + case 0x00: + materialCount = 1; + break; + + case 0x01: + materialCount = reader.readU8(); + break; + + case 0x02: + materialCount = reader.readU16(); + break; + + case 0x03: + materialCount = reader.readU32(); + break; + } + + struct MaterialInfo + { + uint8_t textureDimensions = 0; + uint32_t numberOfTextureLayers = 0; + uint32_t originalShadingId = 0; + bool hasDiffuseColors = false; + bool hasSpecularColors = false; + QByteArray additionalTextDimensions; + }; + std::vector materialInfos; + + // We will read material info from the data + if (materialTypeCount != 0) + { + for (uint32_t i = 0; i < materialTypeCount; ++i) + { + MaterialInfo materialInfo; + + uint8_t materialFlags = reader.readU8(); + materialInfo.textureDimensions = materialFlags & 0x03; + uint8_t originalShadingIdBytes = (materialFlags >> 2) & 0x03; + uint8_t numberOfTextureLayersBytes = (materialFlags >> 4) & 0x03; + materialInfo.hasDiffuseColors = (materialFlags & 0x40); + materialInfo.hasSpecularColors = (materialFlags & 0x80); + + switch (numberOfTextureLayersBytes) + { + case 0: + materialInfo.numberOfTextureLayers = reader.readU8(); + break; + case 1: + materialInfo.numberOfTextureLayers = reader.readU16(); + break; + case 2: + materialInfo.numberOfTextureLayers = reader.readU24(); + break; + case 3: + materialInfo.numberOfTextureLayers = reader.readU32(); + break; + } + + switch (originalShadingIdBytes) + { + case 0: + materialInfo.originalShadingId = reader.readU8(); + break; + case 1: + materialInfo.originalShadingId = reader.readU16(); + break; + case 2: + materialInfo.originalShadingId = reader.readU24(); + break; + case 3: + materialInfo.originalShadingId = reader.readU32(); + break; + } + + uint32_t numberOfAdditionalTextureLayers = materialInfo.numberOfTextureLayers > 0 ? materialInfo.numberOfTextureLayers - 1 : 0; + uint32_t numberOfAdditionalTextureLayersBytes = 0; + + if (numberOfAdditionalTextureLayers % 4 > 0) + { + numberOfAdditionalTextureLayersBytes = numberOfAdditionalTextureLayers / 4 + 1; + } + else + { + numberOfAdditionalTextureLayersBytes = numberOfAdditionalTextureLayers / 4; + } + + if (numberOfAdditionalTextureLayersBytes > 0) + { + materialInfo.additionalTextDimensions = reader.readByteArray(numberOfAdditionalTextureLayersBytes); + } + + materialInfos.emplace_back(std::move(materialInfo)); + } + } + + break; + } + + + block->parseMetadata(metaData, object); + return pointer; +} + } // namespace u3d } // namespace pdf diff --git a/Pdf4QtViewer/CMakeLists.txt b/Pdf4QtViewer/CMakeLists.txt index 59ac69c..f234759 100644 --- a/Pdf4QtViewer/CMakeLists.txt +++ b/Pdf4QtViewer/CMakeLists.txt @@ -61,7 +61,7 @@ GENERATE_EXPORT_HEADER(Pdf4QtViewer PDF4QTVIEWERLIBSHARED_EXPORT EXPORT_FILE_NAME "${CMAKE_BINARY_DIR}/${INSTALL_INCLUDEDIR}/pdf4qtviewer_export.h") -target_link_libraries(Pdf4QtViewer PRIVATE Pdf4QtLib Qt6::Core Qt6::Gui Qt6::Widgets Qt6::PrintSupport Qt6::TextToSpeech Qt6::Xml Qt6::OpenGLWidgets Qt6::3DCore Qt6::3DRender Qt6::3DInput Qt6::3DLogic Qt6::3DExtras) +target_link_libraries(Pdf4QtViewer PRIVATE Pdf4QtLib Qt6::Core Qt6::Gui Qt6::Widgets Qt6::PrintSupport Qt6::TextToSpeech Qt6::Xml Qt6::OpenGLWidgets Qt6::3DCore Qt6::3DRender Qt6::3DInput Qt6::3DLogic Qt6::3DExtras Qt6::ShaderTools) target_include_directories(Pdf4QtViewer INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories(Pdf4QtViewer PUBLIC ${CMAKE_BINARY_DIR}/${INSTALL_INCLUDEDIR}) diff --git a/prc/prc_format.xml b/prc/prc_format.xml index 2c13d27..759e9f1 100644 --- a/prc/prc_format.xml +++ b/prc/prc_format.xml @@ -9,6 +9,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -607,7 +646,7 @@ - + @@ -1667,7 +1706,436 @@ - str. 146 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +