/////////////////////////////////////////////////////////////////////////////// // 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 and writes a DGN file. */ /* */ /* Calling sequence: */ /* */ /* ExDgnPdfExport -flags */ /* */ /************************************************************************/ #include "OdaCommon.h" #include "StaticRxObject.h" #include "RxInit.h" #include "RxDynamicModule.h" #include "DynamicLinker.h" #include "ExDgnServices.h" #include "ExDgnHostAppServices.h" #include "DgDatabase.h" #include "PdfExport.h" #include "RxDynamicModule.h" #include "diagnostics.h" #define STL_USING_IOSTREAM #include "OdaSTL.h" #define STD(a) std:: a using namespace TD_PDF_2D_EXPORT; // Auxiliary function to display different messages //void oddgPrintConsoleString(const wchar_t* fmt, ...); /************************************************************************/ /* Define a Custom Services class. */ /* */ /* Combines the platform dependent functionality of */ /* OdExDgnSystemServices and OdExDgnHostAppServices */ /************************************************************************/ class MyServices : public OdExDgnSystemServices, public OdExDgnHostAppServices { protected: ODRX_USING_HEAP_OPERATORS(OdExDgnSystemServices); 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(); } }; /************************************************************************/ /* User defined function to write a message */ /* to the console for each ODA_ASSERT */ /************************************************************************/ static void customAssertFunc(const char* expr, const char* fileName, int nLine) { printf( "Assertion has occurs:\n" " Expression: %s\n" " Filename: %s\n" " Line number: %d\n", expr, fileName, nLine ); } static void myTrace(const OdChar* debugString) { #if defined(_DEBUG) && defined(_WIN32) OutputDebugStringW((const wchar_t*)debugString); #endif } #ifndef _TOOLKIT_IN_DLL_ ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(OdDgnModule); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(OdDgn7IOModuleImpl); //this library allows to read V7 files ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(OdRxThreadPoolService); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(ExRasterModule); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(OdRasterProcessingServicesImpl); #if defined(OD_HAS_OPENGL) ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(WinOpenGLModule); #endif ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(BitmapModule); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(OdPdfExportModule); ODRX_BEGIN_STATIC_MODULE_MAP() ODRX_DEFINE_STATIC_APPLICATION(L"TG_Db", OdDgnModule) ODRX_DEFINE_STATIC_APPLICATION(L"TG_Dgn7IO", OdDgn7IOModuleImpl) ODRX_DEFINE_STATIC_APPLICATION(OdThreadPoolModuleName, OdRxThreadPoolService) ODRX_DEFINE_STATIC_APPMODULE(RX_RASTER_SERVICES_APPNAME, ExRasterModule) ODRX_DEFINE_STATIC_APPMODULE(OdRasterProcessorModuleName, OdRasterProcessingServicesImpl) #if defined(OD_HAS_OPENGL) ODRX_DEFINE_STATIC_APPMODULE(OdWinOpenGLModuleName, WinOpenGLModule) #endif ODRX_DEFINE_STATIC_APPMODULE(OdWinBitmapModuleName, BitmapModule) ODRX_DEFINE_STATIC_APPMODULE(OdPdfExportModuleName, OdPdfExportModule) ODRX_END_STATIC_MODULE_MAP() #endif void fillLayoutList(OdArray& layouts, OdDgDatabasePtr& pDb, bool bAllLayouts, bool bAllViews) { if(bAllLayouts) // all { OdDgModelTablePtr pModelTable = pDb->getModelTable(); OdDgViewGroupTablePtr pViewGroupTable = pDb->getViewGroupTable(OdDg::kForRead); std::set setUsedModels; OdArray arrLayoutNames; if(!pViewGroupTable.isNull()) { OdDgElementIteratorPtr pVGIter = pViewGroupTable->createIterator(); for(; !pVGIter->done(); pVGIter->step()) { OdDgViewGroupPtr pVG = pVGIter->item().openObject(OdDg::kForRead); OdString layoutName = pVG->getName(); bool bAddLayout = true; for(OdUInt32 k = 0; k < arrLayoutNames.size(); k++) { if(arrLayoutNames[k] == layoutName) { bAddLayout = false; break; } } if(!bAddLayout) continue; arrLayoutNames.push_back(layoutName); if(bAllViews) { OdDgElementIteratorPtr pViewIter = pVG->createIterator(); for(; !pViewIter->done(); pViewIter->step()) { OdDgViewPtr pView = pViewIter->item().openObject(OdDg::kForRead); if(!pView.isNull() && pView->getVisibleFlag()) { OdString viewIndex; viewIndex.format(L"%d", pView->getIndex()); OdString strLayoutAndView; strLayoutAndView = layoutName + L"$" + viewIndex; layouts.push_back(strLayoutAndView); OdDgElementId idViewModel = pView->getModelId(); std::set::const_iterator pModelFindIter = setUsedModels.find(idViewModel); if(pModelFindIter == setUsedModels.end()) setUsedModels.insert(idViewModel); } } } else { layouts.push_back(layoutName); } } } } else if(bAllViews) { OdDgModelPtr pModel; OdDgElementId idModel = pDb->getActiveModelId(); OdDgElementId idActiveViewGroup = pDb->getActiveViewGroupId(); if(!idModel.isNull()) pModel = idModel.openObject(OdDg::kForRead); if(!pModel.isNull()) { OdString name = pModel->getName(); OdDgElementId idViewGroup = idActiveViewGroup; if(idViewGroup.isNull()) idViewGroup = pModel->getViewGroup(true); if(!idViewGroup.isNull()) { OdDgViewGroupPtr pViewGroup = idViewGroup.openObject(OdDg::kForRead); if(!pViewGroup.isNull()) { OdDgElementIteratorPtr pViewIter = pViewGroup->createIterator(); for(; !pViewIter->done(); pViewIter->step()) { OdDgViewPtr pView = pViewIter->item().openObject(OdDg::kForRead); if(!pView.isNull() && pView->getVisibleFlag()) { OdString strLayoutAndView; strLayoutAndView.format(L"$%d", pView->getIndex()); strLayoutAndView = name + strLayoutAndView; layouts.push_back(strLayoutAndView); } } } } } } } /************************************************************************/ /* 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 if(argc < 4) { STD(cout) << "usage: OdPdfExportEx [options]" << STD(endl) << "export flags is a bit mask:" << STD(endl) << " 1st bit - export all layouts, otherwise active layout " << STD(endl) << " 2nd bit - export all views, otherwise active view " << STD(endl) << " 3rd bit - 1bpp images as in Microstation" << STD(endl) << " 4th bit - geometry resolution as in Microstation" << STD(endl) << " 5th bit - set zoom to extents " << STD(endl) << " 6th bit - use embedded TTF fonts " << STD(endl) << " 7th bit - use embedded optimized TTF fonts " << STD(endl) << " 8th bit - TTF fonts as a geometry " << STD(endl) << " 9th bit - RSC fonts as a geometry " << STD(endl) << "10th bit - enable layer support " << STD(endl) << "11th bit - add invisible layers to pdf document " << STD(endl) << "12th bit - add extents bounding box " << STD(endl) << "13th bit - encoded (less size) " << STD(endl) << "14th bit - ASCII hex encoded " << STD(endl) << "15th bit - use hidden line removal algorithm " << STD(endl) << "16th bit - make TTF text searchable (if it exported as geometry) " << STD(endl) << "17th bit - make SHX text searchable (if it exported as geometry) " << STD(endl) << "18th bit - export hyperlinks " << STD(endl) << "19th bit - export as WEB PDF (linearized) " << STD(endl) << "20th bit - Measuring scale in PDF " << STD(endl) << "options could be:" << STD(endl) << " --paper A4|Letter|Custom - paper size (work only if zoom to extents flag is enabled) " << STD(endl) << " --paper-width XX - custom paper width of XX millimeters " << STD(endl) << " --paper-height YY - custom paper height of YY millimeters " << STD(endl) << " --geom-res YY - vector resolution is YY dpi " << STD(endl) << " --color-res YY - resolution of color raster images is YY dpi " << STD(endl) << " --bw-res YY - resolution of monochrome raster images is YY dpi " << STD(endl) << " --color-policy - AsIs(default)|Mono|Gray" << STD(endl) << " --archived - None(default)|1b|2b" << STD(endl) << " --geoMeasure OFF(default)|ON export GeoSpatial data if present(Measuring scale should be turned on)" << " --split OFF(default)|ON export each layout in separate pdf file" ; } else { #ifdef OD_HAVE_SETLOCALE_FUNC /********************************************************************/ /* For correct Unicode translation, apply the current system locale.*/ /********************************************************************/ setlocale(LC_ALL, ""); /********************************************************************/ /* But use usual conversion for scanf()/sprintf() */ /********************************************************************/ setlocale(LC_NUMERIC, "C"); #endif #ifndef _TOOLKIT_IN_DLL_ ODRX_INIT_STATIC_MODULE_MAP(); #endif /********************************************************************/ /* Create a custom Services instance. */ /********************************************************************/ OdStaticRxObject svcs; odrxInitialize(&svcs); odSetTraceFunc(&myTrace); /********************************************************************/ /* Display the Product and Version that created the executable */ /********************************************************************/ STD(cout) << "Developed using " << (const char*)svcs.product() << ", " << (const char*)svcs.versionString() << STD(endl); STD(cout) << "Export flags:" << STD(endl); /********************************************************************/ /* 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"); bool bActiveView(GETBIT(flags, 2)); COMMENTFLAG(bActiveLayout, "Active view only"); COMMENTFLAG(!bActiveView, "All views"); bool bMonoImagesAsTransparencyMask(GETBIT(flags, 4)); COMMENTFLAG(bMonoImagesAsTransparencyMask, "Mono images as transparency mask"); bool bDPI720(GETBIT(flags, 8)); COMMENTFLAG(bDPI720, "Adaptive 720 DPI"); bool bZoomToExtents(GETBIT(flags, 16)); COMMENTFLAG(bZoomToExtents, "Zoom to extents"); bool bEmbededTTF(GETBIT(flags, 32)); COMMENTFLAG(bEmbededTTF, "Embeded TTF"); bool bEmbededOptimizedTTF(GETBIT(flags, 64)); COMMENTFLAG(bEmbededOptimizedTTF, "Optimized embeded 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; bool bSplitLayouts = false; STD(map) < OdString, OdString > paramsMap; int curIndex = 4; if((argc - curIndex) % 2) { STD(cout) << "Wrong options count." << STD(endl); return 1; } 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; } auto iterColor = paramsMap.find(L"--color-policy"); if(iterColor != paramsMap.end()) { 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; } 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") { ok = true; // OdGsPageParams is A4 by default } else if(iterPaper->second == L"Letter") { pageParams.set(215.9, 279.4); 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); ok = true; } } // if(!ok) // { // STD(cout) << "Wrong options." << STD(endl); // return 1; // } } try { /******************************************************************/ /* Create a Pdf export module */ /******************************************************************/ OdPdfExportModulePtr pModule = ::odrxDynamicLinker()->loadApp(OdPdfExportModuleName); /******************************************************************/ /* Create a database and load the drawing into it. */ /******************************************************************/ ::odrxDynamicLinker()->loadModule(L"TG_Db", false); OdString srcFileName = argv[1]; OdDgDatabasePtr pDb = svcs.readFile(srcFileName); if(!pDb.isNull()) { /****************************************************************/ /* Initialize the conversion parameters */ /****************************************************************/ PDFExportParams params; 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))); params.setMonoImagesAsMask(bMonoImagesAsTransparencyMask); params.set720DPIMode(bDPI720); if(bMeasuring && bGeoMeasureMode) params.setMeasuringType(PDFExportParams::kGEO); if(!bExtentsBoundingBox) SETBIT(params.m_reserved1, 1, 1); params.setTitle("Batch PDF File"); params.setAuthor("OdPdfTestEx"); params.setCreator("Teigha"); params.setGeomDPI(iGeomRes); params.setColorImagesDPI(iColorRes); params.setBWImagesDPI(iBWRes); params.setArchived(pdfAmode); if(cp != PDFExportParams::kNoPolicy) params.setColorPolicy(cp); pDb->startUndoRecord(); pDb->startTransaction(); fillLayoutList(params.layouts(), pDb, !bActiveLayout, !bActiveView); if(pageParams.getPaperHeight() && pageParams.getPaperWidth()) { pDb->setPaperSize(pageParams.getPaperWidth(), pageParams.getPaperHeight()); params.pageParams().resize(params.layouts().size(), pageParams); } //pDb->setMargins(m_dTopMargin, m_dBottomMargin, m_dLeftMargin, m_dRightMargin); pDb->setLayoutDataFromSheetModelPaperSettingsFlag(true); OdDg::OdDgPlotType uOldPlotType = pDb->getPlotType(); OdUInt32 nPages = params.layouts().size(); ODA_ASSERT(nPages); { if(params.exportFlags() & PDFExportParams::kZoomToExtentsMode) pDb->setPlotType(OdDg::kExtents); else pDb->setPlotType(OdDg::kView); OdUInt32 errCode = 0; if(bSplitLayouts && params.layouts().size() > 1) { const OdStringArray& layouts = params.layouts(); const OdArray& pageParamsArr = params.pageParams(); for(OdUInt32 index = 0; index < layouts.size(); index++) { params.layouts().clear(); params.pageParams().clear(); params.layouts().append(layouts.at(index)); params.pageParams().append(pageParamsArr.at(index)); { OdPdfExportPtr pExporter = pModule->create(); if(pExporter.isNull()) { printf("\nCannot create Pdf Exporter\n"); return 0; } OdString outFile(argv[1]), outPath(argv[2]); #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(odrxSystemServices()->createFile(outFile, Oda::kFileWrite, Oda::kShareDenyNo, Oda::kCreateAlways)); errCode = pExporter->exportPdf(params); if(errCode != 0) { OdString errMes = pExporter->exportPdfErrorCode(errCode); printf("\nexportPdf error returned : 0x%x. \n%s", (unsigned)errCode, (const char*)errMes); return 0; } } } } else { OdPdfExportPtr pExporter = pModule->create(); if(pExporter.isNull()) { printf("\nCannot create Pdf Exporter\n"); return 0; } params.setOutput(odrxSystemServices()->createFile(argv[2], Oda::kFileWrite, Oda::kShareDenyNo, Oda::kCreateAlways)); errCode = pExporter->exportPdf(params); if(errCode != 0) { OdString errMes = pExporter->exportPdfErrorCode(errCode); printf("\nexportPdf error returned : 0x%x. \n%s", (unsigned)errCode, (const char*)errMes); } } } pDb->setPlotType(uOldPlotType); pDb->endTransaction(); pDb->undo(); } } catch(OdError& err) { OdString msg = err.description(); STD(cout) << "Error: " << (const char*)msg << STD(endl) << STD(endl); } catch(...) { STD(cout) << "Unknown Error." << STD(endl) << STD(endl); return 0; } odrxUninitialize(); } return 0; }