/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// /************************************************************************/ /* This console application reads a DWG/DXF file and saves it to */ /* a PDF file with the specified export options */ /* */ /* */ /* Calling sequence: */ /* */ /* OdPdfExportEx */ /* */ /************************************************************************/ #ifdef WD_WIN_SYSTEM #include #include #endif #include #define STL_USING_IOSTREAM #include "OdaSTL.h" #define STD(a) std:: a #include "OdaCommon.h" #include "DbDatabase.h" #include "DbBlockTableRecord.h" #include "DbDictionary.h" #include "DbViewport.h" #include "ExSystemServices.h" #include "ExHostAppServices.h" #include "RxDynamicModule.h" #include "PdfExport.h" #include #include "tinyxml/tinyxml.h" #include "DbPlotSettingsValidator.h" #ifdef ODA_WINDOWS #include #endif #ifdef OD_HAVE_CONSOLE_H_FILE #include #endif using namespace TD_PDF_2D_EXPORT; /************************************************************************/ /* Define a module map for statically linked modules: */ /************************************************************************/ #ifndef _TOOLKIT_IN_DLL_ ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(ModelerModule); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(OdRecomputeDimBlockModule); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(RasterExportModule); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(BitmapModule); #if defined(OD_HAS_OPENGL) ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(WinOpenGLModule); #endif #if defined(ODA_WINDOWS) #if defined(_MSC_VER) ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(OdOleItemHandlerModuleImpl); #endif #endif #if defined (ODA_UNIXOS) ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(OdOleSsItemHandlerModuleImpl); #endif ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(ExRasterModule); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(OdPsPlotStyleServicesImpl); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(OdPlotSettingsValidatorModule); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(OdRasterProcessingServicesImpl); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(OdPdfExportModule); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(TD_IbModule); //needed for embedded raster images ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(TD_IdViewObjModule); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(ModelDocObjModule); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(DbConstraints_Module); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(TD_DynBlocksModule); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(TD_3DSolidHistoryModule); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(OdSpatialReferenceModule); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(OdGeoDataModule); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(GeolocationObjModule); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(OdDbGeoMapPEModule); #if defined (PDFIUM_MODULE_ENABLED) ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(PdfUnderlayModule); #endif ODRX_BEGIN_STATIC_MODULE_MAP() ODRX_DEFINE_STATIC_APPMODULE(OdModelerGeometryModuleName, ModelerModule) ODRX_DEFINE_STATIC_APPLICATION(OdRecomputeDimBlockModuleName, OdRecomputeDimBlockModule) ODRX_DEFINE_STATIC_APPMODULE(OdRasterExportModuleName, RasterExportModule) ODRX_DEFINE_STATIC_APPMODULE(OdWinBitmapModuleName, BitmapModule) #if defined(OD_HAS_OPENGL) ODRX_DEFINE_STATIC_APPMODULE(OdWinOpenGLModuleName, WinOpenGLModule) #endif #if defined(ODA_WINDOWS) #if defined(_MSC_VER) ODRX_DEFINE_STATIC_APPMODULE(OdOleItemHandlerModuleName, OdOleItemHandlerModuleImpl) #endif #endif #if defined (ODA_UNIXOS) ODRX_DEFINE_STATIC_APPMODULE(OdOleSsItemHandlerModuleName, OdOleSsItemHandlerModuleImpl) #endif ODRX_DEFINE_STATIC_APPMODULE(RX_RASTER_SERVICES_APPNAME, ExRasterModule) ODRX_DEFINE_STATIC_APPMODULE(OdPlotSettingsValidatorModuleName, OdPlotSettingsValidatorModule) ODRX_DEFINE_STATIC_APPLICATION(ODPS_PLOTSTYLE_SERVICES_APPNAME, OdPsPlotStyleServicesImpl) ODRX_DEFINE_STATIC_APPMODULE(OdRasterProcessorModuleName, OdRasterProcessingServicesImpl) ODRX_DEFINE_STATIC_APPMODULE(OdPdfExportModuleName, OdPdfExportModule) ODRX_DEFINE_STATIC_APPMODULE(OdAcIdViewObjModuleName, TD_IdViewObjModule) ODRX_DEFINE_STATIC_APPMODULE(OdAeciIbModuleName, TD_IbModule) //needed for embedded raster images ODRX_DEFINE_STATIC_APPMODULE(OdModelDocObjModuleName, ModelDocObjModule) ODRX_DEFINE_STATIC_APPMODULE(DbConstraintsModuleName, DbConstraints_Module) ODRX_DEFINE_STATIC_APPMODULE(OdDynBlocksModuleName, TD_DynBlocksModule) ODRX_DEFINE_STATIC_APPMODULE(Od3DSolidHistoryTxModuleName, TD_3DSolidHistoryModule) ODRX_DEFINE_STATIC_APPMODULE(OdSpatialReferenceModuleName, OdSpatialReferenceModule) ODRX_DEFINE_STATIC_APPMODULE(OdGeoDataModuleName, OdGeoDataModule) ODRX_DEFINE_STATIC_APPLICATION(OdGeolocationObjModuleName, GeolocationObjModule) ODRX_DEFINE_STATIC_APPLICATION(OdGeoMapPEModuleName, OdDbGeoMapPEModule) #if defined (PDFIUM_MODULE_ENABLED) ODRX_DEFINE_STATIC_APPLICATION(OdPdfiumModuleName, PdfUnderlayModule) #endif ODRX_END_STATIC_MODULE_MAP() #endif //---------------------------------------------------------------------------------- class MyServices : public ExSystemServices, public ExHostAppServices { protected: ODRX_USING_HEAP_OPERATORS(ExSystemServices); private: /************************************************************************/ /* Compile password support for R18 Drawings */ /************************************************************************/ #if defined(_MSC_VER) && !(defined(_WINRT)) bool getPassword(const OdString& dwgName, bool /*isXref*/, OdPassword& password) { char buff[_MAX_PATH] = {0}; STD(cout) << "Enter password to open drawing: " << STD(endl); ::CharToOemA((const char*)dwgName, buff); STD(cout) << " " << buff << STD(endl); STD(cin).get(buff, '\n').get(); wchar_t pwdBuff[_MAX_PATH] = {0}; // convert to upper case unicode: ::OemToCharW( buff, pwdBuff ); ::CharUpperW( pwdBuff ); password = pwdBuff; return !password.isEmpty(); } #endif public: OdGsDevicePtr gsBitmapDevice(OdRxObject* /*pViewObj*/ = NULL, OdDbBaseDatabase* /*pDb*/ = NULL, OdUInt32 flags = 0) { OdGsModulePtr pM; if(GETBIT(flags, kFor2dExportRender)) { if(GETBIT(flags, kFor2dExportRenderHLR)) return OdGsDevicePtr(); pM = ::odrxDynamicLinker()->loadModule(OdWinGLES2ModuleName); } if(pM.isNull()) pM = ::odrxDynamicLinker()->loadModule(OdWinOpenGLModuleName); if(pM.isNull()) pM = ::odrxDynamicLinker()->loadModule(OdWinBitmapModuleName); if(pM.isNull()) return OdGsDevicePtr(); return pM->createBitmapDevice(); } OdString findFile(const OdString& pcFilename, OdDbBaseDatabase* pDb = NULL, OdDbBaseHostAppServices::FindFileHint hint = kDefault) override { OdString sFile = ExHostAppServices::findFile(pcFilename, pDb, hint); #if defined(_WIN32) && !defined(__BORLANDC__) if(sFile.isEmpty()) { OdString sPath = _tgetenv(L"DDPLOTSTYLEPATHS"); sPath.trimLeft(L"."); sPath.trimRight(L"\\"); sPath += L"\\"; sPath += pcFilename; if(accessFile(sPath, Oda::kFileRead)) sFile = sPath; } #endif return sFile; }; }; // Prints usage information for the command-line tool. void printHelp() { odPrintConsoleString(L"usage: \n"); odPrintConsoleString(L"OdPdfExportEx --config \n"); odPrintConsoleString(L"or\n"); odPrintConsoleString(L"OdPdfExportEx [options]\n\n"); odPrintConsoleString(L" is a bitmask integer. Add values for desired options:\n"); odPrintConsoleString(L" 1st bit (1) - export active layout, otherwise all layouts.\n"); odPrintConsoleString(L" 2nd and 3rd bits (2 and 4) - export solid non gradient hatche.s\n"); odPrintConsoleString(L" 0 - export solid non gradient hatches as bitmaps.\n"); odPrintConsoleString(L" 1 - export solid non gradient hatches using vectorizer.\n"); odPrintConsoleString(L" 2 - export solid non gradient hatches as pdf paths.\n"); odPrintConsoleString(L" 4th bit (8) - export gradient hatches using vectorizer, otherwise as bitmaps.\n"); odPrintConsoleString(L" 5th bit (16) - set zoom to extents.\n"); odPrintConsoleString(L" 6th bit (32) - Embed TrueType fonts.\n"); odPrintConsoleString(L" 7th bit (64) - use embedded optimized TrueType fonts.\n"); odPrintConsoleString(L" 8th bit (128) - TrueType fonts exported as a geometry.\n"); odPrintConsoleString(L" 9th bit (256) - SHX fonts exported as a geometry.\n"); odPrintConsoleString(L" 10th bit (512) - enable layer support.\n"); odPrintConsoleString(L" 11th bit (1024) - add invisible layers to pdf document.\n"); odPrintConsoleString(L" 12th bit (2048) - add extents bounding box.\n"); odPrintConsoleString(L" 13th bit (4096) - encoded (less size).\n"); odPrintConsoleString(L" 14th bit (8192) - ASCII hex encoded.\n"); odPrintConsoleString(L" 15th bit (16384) - use hidden line removal (HLR) algorithm.\n"); odPrintConsoleString(L" 16th bit (32768) - use simple geometry optimization algorithm.\n"); odPrintConsoleString(L" 17th bit (65536) - make TTF text searchable (if it exported as geometry).\n"); odPrintConsoleString(L" 18th bit (131072) - make SHX text searchable (if it exported as geometry).\n"); odPrintConsoleString(L" 19th bit (262144) - Export hyperlinks from the drawing.\n"); odPrintConsoleString(L" 20th bit (524288) - Create a linearized (web-optimized) PDF.\n"); odPrintConsoleString(L" 21th bit (1048576) - Enable measuring tool in the PDF.\n"); odPrintConsoleString(L"\n\nExample: flags=529 (1+16+512) exports active layout, zoomed to extents, with layers.\n\n"); odPrintConsoleString(L"Optional key-value parameters [options]:\n"); odPrintConsoleString(L" --paper A4|Letter|Custom - paper size (work only if zoom to extents flag is enabled)\n"); odPrintConsoleString(L" --paper-width XX - Custom paper width in mm.\n"); odPrintConsoleString(L" --paper-height YY - Custom paper height in mm.\n"); odPrintConsoleString(L" --geom-res YY - Vector resolution in DPI (e.g., 600).\n"); odPrintConsoleString(L" --color-res YY - Color image resolution in DPI (e.g., 400).\n"); odPrintConsoleString(L" --bw-res YY - B&W image resolution in DPI (e.g., 400).\n"); odPrintConsoleString(L" --color-policy - AsIs(default)|MonoPlotstyle(supports in Windows only)|Mono|Gray\n"); odPrintConsoleString(L" --archived - None(default)|1b|2b|3b\n"); odPrintConsoleString(L" --geoMeasure - OFF(default)|ON export GeoSpatial data if present(Measuring scale should be turned on)\n"); odPrintConsoleString(L" --split - OFF(default)|ON export each layout in separate pdf file\n\n"); } // Configures the PDFExportParams object based on the bitmask and optional arguments. bool applyCommandLineParams(PDFExportParams& params, OdDbDatabasePtr& pDb, OdDbPlotSettingsValidatorPtr& pValidator, bool& bSplitLayouts, int argc, #if defined(OD_USE_WMAIN) wchar_t* argv[]) #else char* argv[]) #endif { odPrintConsoleString(L"Export flags:\n"); /********************************************************************/ /* Process command line parameters */ /********************************************************************/ int flags = atoi(OdString(argv[3])); #define COMMENTFLAG(AFLAG, ACOMMENTTRUE) if(AFLAG) STD(cout) << ACOMMENTTRUE << STD(endl) bool bActiveLayout(GETBIT(flags, 1)); COMMENTFLAG(bActiveLayout, "Active layout only"); COMMENTFLAG(!bActiveLayout, "All layouts"); int nSolidHatchExpType(0); SETBIT(nSolidHatchExpType, 1, GETBIT(flags, 2)); COMMENTFLAG(!GETBIT(flags, 2) && !GETBIT(flags, 4), "Export solid hatches as bitmaps"); SETBIT(nSolidHatchExpType, 2, GETBIT(flags, 4)); COMMENTFLAG(!GETBIT(flags, 2) && GETBIT(flags, 4), "Export solid hatches as pdf paths"); COMMENTFLAG(GETBIT(flags, 2) && !GETBIT(flags, 4), "Export solid hatches using vectorizer"); int nGradientHatchExpType(0); SETBIT(nGradientHatchExpType, 1, GETBIT(flags, 8)); COMMENTFLAG(!GETBIT(flags, 8), "Export gradient hatches as bitmaps"); COMMENTFLAG(GETBIT(flags, 8), "Export gradient hatches using vectorizer"); bool bZoomToExtents(GETBIT(flags, 16)); COMMENTFLAG(bZoomToExtents, "Zoom to extents"); bool bEmbededTTF(GETBIT(flags, 32)); COMMENTFLAG(bEmbededTTF, "Embedded TTF"); bool bEmbededOptimizedTTF(GETBIT(flags, 64)); COMMENTFLAG(bEmbededOptimizedTTF, "Optimized embedded TTF mode"); bool bTTFAsAGeometry(GETBIT(flags, 128)); COMMENTFLAG(bTTFAsAGeometry, "TTF as geometry"); bool bSHXAsAGeometry(GETBIT(flags, 256)); COMMENTFLAG(bSHXAsAGeometry, "SHX as geometry"); bool bEnableLayersSupport(GETBIT(flags, 512)); COMMENTFLAG(bEnableLayersSupport, "Enable layers"); bool bIncludeOffLayers(GETBIT(flags, 1024)); COMMENTFLAG(bIncludeOffLayers, "Include invisible layers to pdf document"); bool bExtentsBoundingBox(GETBIT(flags, 2048)); COMMENTFLAG(bExtentsBoundingBox, "Show extents bounding box"); bool bEncoded(GETBIT(flags, 4096)); COMMENTFLAG(bEncoded, "Encoded"); bool bASCIIhexEncoded(GETBIT(flags, 8192)); COMMENTFLAG(bASCIIhexEncoded, "ASCII encoded"); bool bUseHiddenLineAlgo(GETBIT(flags, 16384)); COMMENTFLAG(bUseHiddenLineAlgo, "Use hidden line removal algorithm"); bool bUseSimpleGeomOpt(GETBIT(flags, 32768)); COMMENTFLAG(bUseSimpleGeomOpt, "Enable simple geometry optimization"); bool bSearchableTTF(GETBIT(flags, 65536) && GETBIT(flags, 128)); COMMENTFLAG(bSearchableTTF, "Make TTF searchable"); bool bSearchableSHX(GETBIT(flags, 131072) && GETBIT(flags, 256)); COMMENTFLAG(bSearchableSHX, "Make SHX searchable"); bool bHyperlinks(GETBIT(flags, 262144)); COMMENTFLAG(bHyperlinks, "Export Hyperlinks"); bool bLinearized(GETBIT(flags, 524288)); COMMENTFLAG(bLinearized, "Export as WEB PDF"); bool bMeasuring(GETBIT(flags, 1048576)); COMMENTFLAG(bMeasuring, "Measuring scale in PDF"); bool bMonoPalette = false; OdUInt16 iGeomRes = 600; OdUInt16 iColorRes = 400; OdUInt16 iBWRes = 400; PDFExportParams::ColorPolicy cp = PDFExportParams::kNoPolicy; PDFExportParams::PDF_A_mode pdfAmode = PDFExportParams::kPDFA_None; bool bGeoMeasureMode = false; bSplitLayouts = false; STD(map) < OdString, OdString > paramsMap; int curIndex = 4; if((argc - curIndex) % 2) { odPrintConsoleString(L"Error: Wrong options count.\n"); return false; } while(curIndex + 1 < argc) { paramsMap[OdString(argv[curIndex])] = OdString(argv[curIndex + 1]); curIndex += 2; } auto iterGeomRes = paramsMap.find(L"--geom-res"); if(iterGeomRes != paramsMap.end()) { iGeomRes = OdUInt16(atoi(iterGeomRes->second)); if(iGeomRes < 72) iGeomRes = 72; } auto iterColorRes = paramsMap.find(L"--color-res"); if(iterColorRes != paramsMap.end()) { iColorRes = OdUInt16(atoi(iterColorRes->second)); if(iColorRes < 72) iColorRes = 72; if(iColorRes > iGeomRes) iColorRes = iGeomRes; } auto iterBWRes = paramsMap.find(L"--bw-res"); if(iterBWRes != paramsMap.end()) { iBWRes = OdUInt16(atoi(iterBWRes->second)); if(iBWRes < 72) iBWRes = 72; if(iBWRes > iGeomRes) iBWRes = iGeomRes; } auto iterPDFA = paramsMap.find(L"--archived"); if(iterPDFA != paramsMap.end()) { if(iterPDFA->second == L"1b") pdfAmode = PDFExportParams::kPDFA_1b; else if(iterPDFA->second == L"2b") pdfAmode = PDFExportParams::kPDFA_2b; else if(iterPDFA->second == L"3b") pdfAmode = PDFExportParams::kPDFA_3b; } auto iterColor = paramsMap.find(L"--color-policy"); if(iterColor != paramsMap.end()) { if(iterColor->second == L"MonoPlotstyle") { bMonoPalette = true; #ifndef WIN32 odPrintConsoleString(L"Monochrome mode with plotstyles are not supported on non Windows systems yet. Now exiting.\n"); return false; #endif } else if(iterColor->second == L"Mono") cp = PDFExportParams::kMono; else if(iterColor->second == L"Gray") cp = PDFExportParams::kGrayscale; } auto iterGEO = paramsMap.find(L"--geoMeasure"); if(iterGEO != paramsMap.end()) { if(iterGEO->second == L"ON") bGeoMeasureMode = true; } auto iterSplit = paramsMap.find(L"--split"); if(iterSplit != paramsMap.end()) { if(iterSplit->second == L"ON") bSplitLayouts = true; } bool bUsePaperFromOptions(false); auto iterPaper = paramsMap.find(L"--paper"); // Paper definition is works only with zoom to extents flag OdGsPageParams pageParams; // in mm bool ok = false; if(iterPaper != paramsMap.end() && bZoomToExtents) { if(iterPaper->second == L"A4") { bUsePaperFromOptions = true; ok = true; // OdGsPageParams is A4 by default } else if(iterPaper->second == L"Letter") { pageParams.set(215.9, 279.4); bUsePaperFromOptions = true; ok = true; } else if(iterPaper->second == L"Custom") { auto iterPaperWidth = paramsMap.find(L"--paper-width"); auto iterPaperHeight = paramsMap.find(L"--paper-height"); if(iterPaperWidth != paramsMap.end() && iterPaperHeight != paramsMap.end()) { double dw(.0), dh(.0); dw = Od_atof(iterPaperWidth->second); dh = Od_atof(iterPaperHeight->second); pageParams.set(dw, dh); bUsePaperFromOptions = true; ok = true; } } if(!ok) { odPrintConsoleString(L"Error: Wrong page param options.\n"); return false; } } params.setDatabase(pDb); params.setVersion(OdPDF::kPDFAuto); params.setExportFlags(PDFExportParams::PDFExportFlags( (bEmbededTTF ? PDFExportParams::kEmbededTTF : 0) | (bEmbededOptimizedTTF ? PDFExportParams::kEmbededOptimizedTTF : 0) | (bTTFAsAGeometry ? PDFExportParams::kTTFTextAsGeometry : 0) | (bSHXAsAGeometry ? PDFExportParams::kSHXTextAsGeometry : 0) | (bEnableLayersSupport ? PDFExportParams::kEnableLayers : 0) | (bIncludeOffLayers ? PDFExportParams::kIncludeOffLayers : 0) | (bUseSimpleGeomOpt ? PDFExportParams::kSimpleGeomOptimization : 0) | (bEncoded ? PDFExportParams::kFlateCompression : 0) | (bASCIIhexEncoded ? PDFExportParams::kASCIIHexEncoding : 0) | (bUseHiddenLineAlgo ? PDFExportParams::kUseHLR : 0) | (bHyperlinks ? PDFExportParams::kExportHyperlinks : 0) | (bLinearized ? PDFExportParams::kLinearized : 0) | (bMeasuring ? PDFExportParams::kMeasuring : 0) | (bZoomToExtents ? PDFExportParams::kZoomToExtentsMode : 0))); params.setSearchableTextType((PDFExportParams::SearchableTextType)((bSearchableSHX ? PDFExportParams::kSHX : 0) | (bSearchableTTF ? PDFExportParams::kTTF : 0))); if(bMeasuring && bGeoMeasureMode) params.setMeasuringType(PDFExportParams::kGEO); if(!bExtentsBoundingBox) SETBIT(params.m_reserved1, 1, 1); params.setTitle("Batch PDF File"); params.setAuthor("OdPdfExportEx"); params.setCreator("ODA SDK"); params.setGeomDPI(iGeomRes); params.setColorImagesDPI(iColorRes); params.setBWImagesDPI(iBWRes); params.setArchived(pdfAmode); params.setGradientHatchesExportType(GETBIT(nGradientHatchExpType, 1) ? PDFExportParams::kDrawing : PDFExportParams::kBitmap); if(cp != PDFExportParams::kNoPolicy) params.setColorPolicy(cp); switch(nSolidHatchExpType) { case 1: // as a drawing (vectorizer) params.setSolidHatchesExportType(PDFExportParams::kDrawing); break; case 2: // as a pdf path params.setSolidHatchesExportType(PDFExportParams::kPdfPaths); break; case 0: // as a bitmap default: params.setSolidHatchesExportType(PDFExportParams::kBitmap); break; } /****************************************************************/ /* Initialize the conversion parameters: Layouts */ /****************************************************************/ if(bActiveLayout) { OdDbBlockTableRecordPtr pLayoutBlock = pDb->getActiveLayoutBTRId().safeOpenObject(); OdDbLayoutPtr pLayout = pLayoutBlock->getLayoutId().safeOpenObject(); params.layouts().push_back(pLayout->getLayoutName()); } else { OdDbDictionaryPtr pLayoutDict = pDb->getLayoutDictionaryId().safeOpenObject(); OdDbDictionaryIteratorPtr pDictIt = pLayoutDict->newIterator(); while(!pDictIt->done()) { OdDbLayoutPtr pLayout = pDictIt->getObject(); OdString sName = pLayout->getLayoutName(); if(pLayout->getBlockTableRecordId() == pDb->getModelSpaceId()) params.layouts().insertAt(0, sName); else { OdDbBlockTableRecordPtr pRec = pLayout->getBlockTableRecordId().safeOpenObject(); OdDbObjectIteratorPtr pObjIt = pRec->newIterator(); bool bEmpty = pObjIt->done(); if(!bEmpty) { if(pLayout->overallVportId().isValid()) { OdDbViewportPtr pOverall = pLayout->overallVportId().safeOpenObject(); // test overall view size. Pdf doesn't export bad view and report error. if(!OdZero(pOverall->viewHeight())) params.layouts().push_back(sName); } else params.layouts().push_back(sName); } } pDictIt->next(); } } /****************************************************************/ /* Initialize the conversion parameters: Monochrome */ /****************************************************************/ // Set current folder to DDPLOTSTYLEPATHS enviroument var to // make possible to find local monochrome.ctb and monochrome.stb // // Or you should to set this env var equal to PrinterStyleSheetDir, // ex. see COdaMfcAppApp::initPlotStyleSheetEnv() #if defined(_WIN32) && !defined(__BORLANDC__) ::odrxDynamicLinker()->loadModule(OdPlotSettingsValidatorModuleName); _tputenv(L"DDPLOTSTYLEPATHS=."); pValidator->refreshLists(0); bool bMonochrome(false); // Get database plot style mode: color-dependent or named bool styleMode = pDb->getPSTYLEMODE(); OdString strMono(styleMode ? "monochrome.ctb" : "monochrome.stb"); if(bMonoPalette) { OdArray PSSlist; pValidator->plotStyleSheetList(PSSlist); unsigned int iSize = PSSlist.size(); if(iSize == 0) { odPrintConsoleString(L"Error: Monochrome mode required files: monochrome.ctb, monochrome.stb to be found. Now exiting.\n"); return false; } const OdChar* mono = strMono.c_str(); for(unsigned int i = 0; i < iSize; ++i) { if(*mono == *PSSlist[i]) { bMonochrome = true; break; } } } if(bMonochrome) { OdDbDictionaryPtr pLayoutDict = pDb->getLayoutDictionaryId().safeOpenObject(); for(unsigned f = 0; f < params.layouts().size(); ++f) { OdDbLayoutPtr pLayout = pLayoutDict->getAt(params.layouts()[f]).safeOpenObject(OdDb::kForWrite); pValidator->setCurrentStyleSheet((OdDbPlotSettings*)pLayout, strMono); } } #endif OdUInt32 nPages = params.layouts().size(); ODA_ASSERT(nPages); if(bZoomToExtents) { OdDbDictionaryPtr pLayoutDict = pDb->getLayoutDictionaryId().safeOpenObject(); if(bUsePaperFromOptions) params.pageParams().resize(nPages, pageParams); else for(unsigned f = 0; f < params.layouts().size(); ++f) { OdDbLayoutPtr pLayout = pLayoutDict->getAt(params.layouts()[f]).safeOpenObject(); OdGeExtents3d xts; // calculate page sides related to A4 and layout extents pLayout->getGeomExtents(xts); double scale(.7071); if(fabs(xts.maxPoint().x - xts.minPoint().x) > OdGeTol().equalPoint()) scale = fabs(xts.maxPoint().y - xts.minPoint().y) / fabs(xts.maxPoint().x - xts.minPoint().x); pageParams.set(pageParams.getPaperWidth(), pageParams.getPaperWidth() * scale); params.pageParams().push_back(pageParams); } } else { OdDbBlockTableRecordPtr pMs = pDb->getModelSpaceId().safeOpenObject(); OdDbObjectPtr pModelLayout = pMs->getLayoutId().safeOpenObject(); OdDbPlotSettingsPtr pPlotSet = OdDbPlotSettings::createObject(); pPlotSet->copyFrom(pModelLayout); double dw(.0), dh(.0); pPlotSet->getPlotPaperSize(dw, dh); pageParams.set(dw, dh); params.pageParams().resize(nPages, pageParams); } return true; } // Helper to get text from a child element, returns OdString static OdString getChildText(TiXmlElement* parent, const char* childName) { if(!parent) return OdString::kEmpty; TiXmlElement* child = parent->FirstChildElement(childName); if(child && child->GetText()) return OdString(child->GetText()); return OdString::kEmpty; } // Helper to convert string to bool static bool toBool(const OdString& str) { return str.iCompare(L"true") == 0 || str.iCompare(L"1") == 0; } static OdPDF::PDFFormatVersions PDFVersionFromString(const OdChar* str) { if(str && *str == L'1' && *(++str) == L'.') { OdChar minor = *(++str) - L'0'; if(minor >= 0 && minor <= 7) { return (OdPDF::PDFFormatVersions)(10 + minor); } } return OdPDF::kPDFAuto; } static PDFExportParams::PDF_A_mode PDF_A_ModeFromString(const OdString& str) { if(!str.isEmpty()) { if(str.iCompare(L"1b") == 0) return PDFExportParams::kPDFA_1b; if(str.iCompare(L"2b") == 0) return PDFExportParams::kPDFA_2b; if(str.iCompare(L"3b") == 0) return PDFExportParams::kPDFA_3b; } return PDFExportParams::kPDFA_None; } static PDFExportParams::PDFShadedViewportExportMode PDFShadedViewportExportModeFromString(const OdString& str) { if(!str.isEmpty()) { if(str.iCompare(L"Tiles") == 0) return PDFExportParams::kExportAsTiles; if(str.iCompare(L"Strips") == 0) return PDFExportParams::kExportAsStrips; } return PDFExportParams::kExportOnePiece; } static PDFExportParams::SearchableTextType SearchableTextTypeFromString(const OdString& str) { if(!str.isEmpty()) { if(str.iCompare(L"TTF") == 0) return PDFExportParams::kTTF; if(str.iCompare(L"SHX") == 0) return PDFExportParams::kSHX; if(str.iCompare(L"ALL") == 0) return (PDFExportParams::SearchableTextType)(PDFExportParams::kTTF | PDFExportParams::kSHX); } return PDFExportParams::kNoSearch; } static PDFExportParams::ExportHatchesType HatchesExportTypeFromString(const OdString& str) { if(!str.isEmpty()) { if(str.iCompare(L"PdfPaths") == 0) return PDFExportParams::kPdfPaths; if(str.iCompare(L"Drawing") == 0) return PDFExportParams::kDrawing; if(str.iCompare(L"Polygons") == 0) return PDFExportParams::kPolygons; } return PDFExportParams::kBitmap; } static PDFExportParams::ColorPolicy ColorPolicyFromString(const OdString& str) { if(!str.isEmpty()) { if(str.iCompare(L"Mono") == 0) return PDFExportParams::kMono; if(str.iCompare(L"Grayscale") == 0) return PDFExportParams::kGrayscale; } return PDFExportParams::kNoPolicy; } void applyDocumentSettings(PDFExportParams& params, TiXmlElement* docSettings) { if(docSettings) { params.setTitle(getChildText(docSettings, "Title")); params.setAuthor(getChildText(docSettings, "Author")); params.setSubject(getChildText(docSettings, "Subject")); params.setKeywords(getChildText(docSettings, "Keywords")); params.setCreator(getChildText(docSettings, "Creator")); params.setProducer(getChildText(docSettings, "Producer")); params.setVersion(PDFVersionFromString(getChildText(docSettings, "PdfVersion"))); params.setArchived(PDF_A_ModeFromString(getChildText(docSettings, "Archived"))); } else { params.setTitle("Batch PDF File"); params.setAuthor("OdPdfExportEx"); params.setCreator("ODA SDK"); params.setVersion(OdPDF::kPDFAuto); } } void applySecuritySettings(PDFExportParams& params, TiXmlElement* secSettings) { if(secSettings) { params.setUserPassword(getChildText(secSettings, "UserPassword")); params.setOwnerPassword(getChildText(secSettings, "OwnerPassword")); params.setAccessPermissionFlags((PDFExportParams::PDFAccessPermissionsFlags)odStrToInt(getChildText(secSettings, "Permissions"))); } } void applyGeneralSettings(PDFExportParams& params, TiXmlElement* generalSettings) { if(generalSettings) { //Parse Pdf export flags bool bEmbedTTF = toBool(getChildText(generalSettings, "EmbeddedTTF")); bool bTTFAsGeom = toBool(getChildText(generalSettings, "TTFasGeometry")); bool bSHXAsGeom = toBool(getChildText(generalSettings, "SHXasGeometry")); bool bGeomOpt = toBool(getChildText(generalSettings, "SimpleGeomOptimization")); bool bEnableLayers = toBool(getChildText(generalSettings, "EnableLayers")); bool bExportOffLayers = toBool(getChildText(generalSettings, "ExportOffLayers")); bool bEmbeddedOptimizedTTF = toBool(getChildText(generalSettings, "EmbeddedOptimizedTTF")); bool bUseHLR = toBool(getChildText(generalSettings, "UseHLR")); bool bEncoded = toBool(getChildText(generalSettings, "Encoded")); bool bHEXEncoded = toBool(getChildText(generalSettings, "HEXEncoded")); bool bExportHyperlinks = toBool(getChildText(generalSettings, "ExportHyperlinks")); bool bZoomToExtents = toBool(getChildText(generalSettings, "ZoomToExtents")); bool bLinearized = toBool(getChildText(generalSettings, "Linearized")); bool bMergeColors = toBool(getChildText(generalSettings, "MergeColors")); bool bEnableMeasuring = toBool(getChildText(generalSettings, "EnableMeasuring")); params.setExportFlags(PDFExportParams::PDFExportFlags( (bEmbedTTF ? PDFExportParams::kEmbededTTF : 0) | (bEmbeddedOptimizedTTF ? PDFExportParams::kEmbededOptimizedTTF : 0) | (bTTFAsGeom ? PDFExportParams::kTTFTextAsGeometry : 0) | (bSHXAsGeom ? PDFExportParams::kSHXTextAsGeometry : 0) | (bEnableLayers ? PDFExportParams::kEnableLayers : 0) | (bExportOffLayers ? PDFExportParams::kIncludeOffLayers : 0) | (bGeomOpt ? PDFExportParams::kSimpleGeomOptimization : 0) | (bEncoded ? PDFExportParams::kFlateCompression : 0) | (bHEXEncoded ? PDFExportParams::kASCIIHexEncoding : 0) | (bUseHLR ? PDFExportParams::kUseHLR : 0) | (bExportHyperlinks ? PDFExportParams::kExportHyperlinks : 0) | (bLinearized ? PDFExportParams::kLinearized : 0) | (bMergeColors ? PDFExportParams::kMergeLines : 0) | (bEnableMeasuring ? PDFExportParams::kMeasuring : 0) | (bZoomToExtents ? PDFExportParams::kZoomToExtentsMode : 0))); //Parse other params params.setSearchableTextType(SearchableTextTypeFromString(getChildText(generalSettings, "SearchableText"))); params.setSolidHatchesExportType(HatchesExportTypeFromString(getChildText(generalSettings, "ExportSolidHatches"))); params.setGradientHatchesExportType(HatchesExportTypeFromString(getChildText(generalSettings, "ExportGradientHatches"))); params.setColorPolicy(ColorPolicyFromString(getChildText(generalSettings, "ColorPolicy"))); if(bEnableMeasuring && toBool(getChildText(generalSettings, "ExportGeoData"))) params.setMeasuringType(PDFExportParams::kGEO); params.setUseGsCache(toBool(getChildText(generalSettings, "UseGsCache"))); if(params.useGsCache()) { params.setParallelVectorization(toBool(getChildText(generalSettings, "UseParallelVectorization"))); params.setUsePdfBlocks(toBool(getChildText(generalSettings, "ExportBlocksAsPdfBlocks"))); if(params.isUsePdfBlocks()) params.setXrefsAsPdfBlocks(toBool(getChildText(generalSettings, "ExportXRefsAsPdfBlocks"))); } params.setSearchableTextAsHiddenText(toBool(getChildText(generalSettings, "SearchableTextAsHiddenText"))); params.setSearchableTextInRenderedViews(toBool(getChildText(generalSettings, "SearchableTextInShadedViewport"))); params.enableBookmarks(toBool(getChildText(generalSettings, "EnableBookmarks"))); params.setStopOnError(toBool(getChildText(generalSettings, "StopOnError"))); } } void applyQualitySettings(PDFExportParams& params, TiXmlElement* qualitySettings) { if(qualitySettings) { params.setGeomDPI((OdUInt16)odStrToInt(getChildText(qualitySettings, "VectorResolution"))); params.setColorImagesDPI((OdUInt16)odStrToInt(getChildText(qualitySettings, "ColorImageResolution"))); params.setBWImagesDPI((OdUInt16)odStrToInt(getChildText(qualitySettings, "BWImageResolution"))); params.setHatchDPI((OdUInt16)odStrToInt(getChildText(qualitySettings, "HatchesImageResolution"))); params.setImageCropping(toBool(getChildText(qualitySettings, "ImageCropping"))); params.setUpscaleImages(toBool(getChildText(qualitySettings, "ImageUpscale"))); params.setDCTCompression(toBool(getChildText(qualitySettings, "DCTCompression"))); params.setDCTQuality((OdUInt16)odStrToInt(getChildText(qualitySettings, "DCTQuality"))); params.setShadedVpExportMode(PDFShadedViewportExportModeFromString(getChildText(qualitySettings, "ShadedViewportExportMode"))); params.setDCTCompressionShadedViewports(toBool(getChildText(qualitySettings, "ShadedViewportDCTCompression"))); params.setTransparentShadedVpBg(toBool(getChildText(qualitySettings, "ShadedViewportBackgroundTransparency"))); params.setMonoImagesAsMask(toBool(getChildText(qualitySettings, "MonochromeImagesAsMask"))); params.set720DPIMode(toBool(getChildText(qualitySettings, "Mode720DPI"))); } } bool applyLayoutSettings(PDFExportParams& params, OdStaticRxObject& svcs, TiXmlElement* pageSettings) { OdArray layoutsArray; OdRxObjectPtrArray databasesArray; if(pageSettings) { TiXmlElement* sources = pageSettings->FirstChildElement("SourceFiles"); if(sources) { TiXmlNode* source = sources->FirstChild("SourceFile"); while(source) { OdString path = source->ToElement()->Attribute("path"); OdDbDatabasePtr pDb = svcs.readFile(path); if(!pDb.isNull()) { TiXmlNode* layouts = source->FirstChild("Layouts"); if(!layouts) //export active layout { OdDbBlockTableRecordPtr pLayoutBlock = pDb->getActiveLayoutBTRId().safeOpenObject(); OdDbLayoutPtr pLayout = pLayoutBlock->getLayoutId().safeOpenObject(); layoutsArray.push_back(pLayout->getLayoutName()); databasesArray.push_back(pDb); } else { TiXmlNode* layout = layouts->FirstChild("Layout"); OdDbDictionaryPtr pLayoutDict = pDb->getLayoutDictionaryId().safeOpenObject(); while(layout) { OdString layoutName = layout->ToElement()->GetText(); if(pLayoutDict->has(layoutName)) { layoutsArray.push_back(layoutName); databasesArray.push_back(pDb); } else odPrintConsoleString(L"Warning: Layout \"%s\" is absent in database \"%s\". The export may not be performed\n", layoutName.c_str(), pDb->getFilename().c_str()); layout = layouts->IterateChildren("Layout", layout); } } } source = sources->IterateChildren("SourceFile", source); } } } if(GETBIT(params.exportFlags(), PDFExportParams::kZoomToExtentsMode)) { TiXmlElement* pages = pageSettings->FirstChildElement("Pages"); if(!pages) { OdArray pageParamsArray; OdGsPageParams pageParams(210, 297); pageParamsArray.resize(layoutsArray.size(), pageParams); params.setPageParams(pageParamsArray); } else { TiXmlNode* page = pages->FirstChild("Page"); OdArray pageParamsArray; OdGsPageParams pageParams; while(page) { double paperWidth = odStrToF(getChildText(page->ToElement(), "PaperWidth")); double paperHeight = odStrToF(getChildText(page->ToElement(), "PaperHeight")); double topMargin = odStrToF(getChildText(page->ToElement(), "TopMargin")); double bottomMargin = odStrToF(getChildText(page->ToElement(), "BottomMargin")); double leftMargin = odStrToF(getChildText(page->ToElement(), "LeftMargin")); double rightMargin = odStrToF(getChildText(page->ToElement(), "RightMargin")); pageParams.set(paperWidth, paperHeight, leftMargin, rightMargin, topMargin, bottomMargin); pageParamsArray.push_back(pageParams); page = pages->IterateChildren("Page", page); } if(pageParamsArray.size() == layoutsArray.size()) params.setPageParams(pageParamsArray); else { odPrintConsoleString(L"Error: Page params count should be equal to Layouts count\n"); layoutsArray.clear(); databasesArray.clear(); pageParamsArray.clear(); return false; } } } if(layoutsArray.size() && databasesArray.size() == layoutsArray.size()) params.setLayouts(layoutsArray, &databasesArray); else { odPrintConsoleString(L"Error: no drawing files or layouts to export are set.\n"); return false; } return true; } // Configures the PDFExportParams object based on the config file. bool applyConfigFileParams(PDFExportParams& params, OdStaticRxObject& svcs, const OdString& configFile, OdString& outPdf, bool& bSplitLayouts) { OdString file = svcs.findFile(configFile); TiXmlDocument xmlDocument; if(!xmlDocument.LoadFile(file)) { odPrintConsoleString(L"Error: Could not load or parse the config file: %s\n", configFile.c_str()); return false; } TiXmlElement* root = xmlDocument.RootElement(); if(!root || strcmp(root->Value(), "PdfExportSettings") != 0) { odPrintConsoleString(L"Error: Invalid config file format. Missing root element.\n"); return false; } bSplitLayouts = false; // --- Document settings --- applyDocumentSettings(params, root->FirstChildElement("DocumentSettings")); // --- Security settings --- applySecuritySettings(params, root->FirstChildElement("SecuritySettings")); // --- General settings --- applyGeneralSettings(params, root->FirstChildElement("GeneralSettings")); // --- Quality settings --- applyQualitySettings(params, root->FirstChildElement("QualitySettings")); // --- page/layout settings --- if(!applyLayoutSettings(params, svcs, root->FirstChildElement("PageSettings"))) return false; // --- other settings --- TiXmlElement* otherSettings = root->FirstChildElement("OtherSettings"); if(otherSettings) { outPdf = getChildText(otherSettings, "OutputFile"); if(outPdf.isEmpty()) { odPrintConsoleString(L"\nError: Output PDF file in section:\n \n \n is not set.\n"); return false; } // This is not a PDFExportParam flag, but a parameter for the main function logic bSplitLayouts = toBool(getChildText(otherSettings, "SeparatePdfForEachLayout")); } else { odPrintConsoleString(L"\nError: Output PDF file in section:\n \n \n is not set.\n"); return false; } return true; } // Executes the PDF export process. bool performExport(PDFExportParams& params, bool bSplitLayouts, const OdString& outPdf) { /******************************************************************/ /* Create a Pdf export module */ /******************************************************************/ OdPdfExportModulePtr pModule = ::odrxDynamicLinker()->loadApp(OdPdfExportModuleName); OdUInt32 errCode = 0; OdPdfExportPtr pExporter = pModule->create(); if(pExporter.isNull()) { odPrintConsoleString(L"\nError: Cannot create Pdf Exporter\n"); return false; } if(bSplitLayouts && params.layouts().size() > 1) { const OdStringArray layouts = params.layouts(); const OdArray pageParamsArr = params.pageParams(); OdRxObjectPtrArray databases = params.databases(); for(OdUInt32 index = 0; index < layouts.size(); index++) { params.layouts().clear(); params.pageParams().clear(); params.clearMultipleDbSettings(); params.layouts().append(layouts.at(index)); params.pageParams().append(pageParamsArr.at(index)); { OdString outFile; if(!params.database()) params.setDatabase(databases.at(index)); outFile = OdDbDatabasePtr(params.database())->getFilename(); OdString outPath(outPdf); #ifdef ODA_WINDOWS OdChar fChar('\\'); #else OdChar fChar('/'); #endif outPath.deleteChars(outPath.reverseFind(fChar) + 1, outPath.getLength() + 1 - outPath.reverseFind(fChar)); outFile.deleteChars(outFile.getLength() - 4, 4); outFile.deleteChars(0, outFile.reverseFind(fChar) + 1); outFile = outPath + outFile + "_" + params.layouts().at(0) + ".pdf"; params.setOutput(odSystemServices()->createFile(outFile, Oda::kFileWrite, Oda::kShareDenyNo, Oda::kCreateAlways)); errCode = pExporter->exportPdf(params); } } } else { params.setOutput(odSystemServices()->createFile(outPdf, Oda::kFileWrite, Oda::kShareDenyNo, Oda::kCreateAlways)); errCode = pExporter->exportPdf(params); } if(errCode != 0) { OdString errMes = pExporter->exportPdfErrorCode(errCode); odPrintConsoleString(L"\nError: exportPdf returned : 0x%x. \n%s", (unsigned)errCode, (const char*)errMes); return false; } return true; } /************************************************************************/ /* Main */ /************************************************************************/ #if defined(OD_USE_WMAIN) int wmain(int argc, wchar_t* argv[]) #else int main(int argc, char* argv[]) #endif { #ifdef OD_HAVE_CCOMMAND_FUNC argc = ccommand(&argv); #endif OdString configFile; if(argc == 3) { OdString paramName(argv[1]); configFile = OdString(argv[2]); if(paramName.compare("--config") || configFile.isEmpty()) { printHelp(); return 0; } } else if(argc < 4) { printHelp(); return 0; } /********************************************************************/ /* For correct Unicode translation, apply the current system locale.*/ /********************************************************************/ setlocale(LC_ALL, ""); /********************************************************************/ /* But use usual conversion for scanf()/sprintf() */ /********************************************************************/ setlocale(LC_NUMERIC, "C"); #ifndef _TOOLKIT_IN_DLL_ ODRX_INIT_STATIC_MODULE_MAP(); #endif /********************************************************************/ /* Create a custom Services instance. */ /********************************************************************/ OdStaticRxObject svcs; odInitialize(&svcs); /********************************************************************/ /* Display the Product and Version that created the executable */ /********************************************************************/ odPrintConsoleString(L"Developed using %s, %s\n", svcs.product().c_str(), svcs.versionString().c_str()); try { #if defined (ODA_UNIXOS) OdRxModulePtr pOLEModule = odrxDynamicLinker()->loadModule(OdOleSsItemHandlerModuleName); if (pOLEModule.isNull()) odPrintConsoleString(L"Ole module hasn't been loaded. Ole objects will not be printed\n"); #endif /****************************************************************/ /* Initialize the conversion parameters */ /****************************************************************/ OdDbDatabasePtr pDb; PDFExportParams params; bool bSplitLayouts; OdString outPdf; // Plot Settings validator creates stylesheets equal to .ctb, .stb files. It's fully depends on DDPLOTSTYLEPATHS env var. OdDbPlotSettingsValidatorPtr pValidator = svcs.plotSettingsValidator(); if(configFile.isEmpty()) { /******************************************************************/ /* Create a database and load the drawing into it. */ /******************************************************************/ pDb = svcs.readFile(argv[1]); if(pDb.isNull()) { odPrintConsoleString(L"Error: Cannot load drawing database\n"); return 0; } if(!applyCommandLineParams(params, pDb, pValidator, bSplitLayouts, argc, argv)) { odPrintConsoleString(L"Error: Cannot apply pdf export parameters from command line.\n\n"); return 0; } } else { if(!applyConfigFileParams(params, svcs, configFile, outPdf, bSplitLayouts)) { odPrintConsoleString(L"Error: Cannot apply pdf export parameters from config file.\n\n"); return 0; } } if(configFile.isEmpty()) outPdf = (argv[2]); if(!performExport(params, bSplitLayouts, outPdf)) { odPrintConsoleString(L"Error: Cannot perform pdf export.\n\n"); return 0; } } catch(OdError& err) { OdString msg = err.description(); odPrintConsoleString(L"Error: %s, \n\n", msg.c_str()); } catch(...) { odPrintConsoleString(L"Unknown Error.\n\n"); return 0; } odUninitialize(); return 0; }