/////////////////////////////////////////////////////////////////////////////// // 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. /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // // PdfExportImplBase.cpp : implementation of the CPdfExportImplBase class // /////////////////////////////////////////////////////////////////////////////// #include "OdaCommon.h" //#ifdef _WIN32 #define STL_USING_IOSTREAM #include "OdaSTL.h" //#endif #include "PdfExportCommon.h" #include "PdfExportImplBase.h" #include "PdfExport.h" #include "PdfExportPE.h" #include "Ge/GeExtents3d.h" #include "OdTimeStamp.h" #include "ColorMapping.h" #include "Pdf2dExportDevice.h" #include "Pdf2dExportView.h" #include "PdfPageNodeDictionary.h" #include "Gs/GsPageParams.h" #include "PdfAux.h" #include "QPDFHelper.h" #include "PdfBookmarksHelper.h" #include "Gi/GiDrawablePtrArray.h" using namespace OdPDF; #define STL_USING_MAP #define STL_USING_VECTOR #include "OdaSTL.h" #include "RxObject.h" #include "AbstractViewPE.h" #include "MemoryStream.h" #include "OdPath.h" namespace TD_PDF_2D_EXPORT { //*************************************************************************** // //*************************************************************************** CPdfExportImplBase::CPdfExportImplBase() { } CPdfExportImplBase::~CPdfExportImplBase() { //Force releasing a device at first. //Order of data releasing is important. m_pDevice.release(); } void CPdfExportImplBase::applyLineweightToDcScale(const PDFExportParams& prms) { OdRxObjectPtr pLayout = OdDbBaseDatabasePEPtr(prms.database())->currentLayout(prms.database()); OdDbBaseLayoutPEPtr pLayoutPE(pLayout); if (pLayoutPE->printLineweights(pLayout)) { OdGsView* pTo = m_pDevice->viewAt(0); pTo->setLineweightToDcScale(prms.getGeomDPI() / kMmPerInch * 0.01); } } static void setLineweightToDcScale(OdGsDevice& device, double scale) { for(int j = 0; j < device.numViews(); ++j) { OdGsView* pView = device.viewAt(j); if(pView) pView->setLineweightToDcScale(scale); } } void CPdfExportImplBase::setupPdfRenderDevices(const PDFExportParams& prms, OdGiDefaultContext* pCtx, PDF2dExportDevice& pdfDevice, OdDbStub* objectId, const OdGsDCRect& clipBox, const OdGeBoundBlock3d& extents, bool bIncludeOffLayers) { OdUInt32 extentsFlag = 0; SETBIT(extentsFlag, OdDbBaseDatabasePE::kExactExtents, !GETBIT(prms.m_reserved1, 1)); SETBIT(extentsFlag, OdDbBaseDatabasePE::kUseViewExtents, prms.useViewExtents()); const bool bZ2E = (GETBIT(prms.exportFlags(), PDFExportParams::kZoomToExtentsMode) != 0); OdDbBaseDatabasePtr pDb = prms.database(); OdDbBaseDatabasePEPtr pDbPE(pDb); for (int nDevice = 0; nDevice < pdfDevice.numRenderDevices(); nDevice++) { OdGsDevice *pRenderDevice = pdfDevice.renderDeviceAt(nDevice); OdGsDevicePtr pDevice = setupPdfRenderDevice(prms, pDbPE, pCtx, *pRenderDevice, bZ2E, extentsFlag, objectId, clipBox, extents, bIncludeOffLayers); pdfDevice.setRenderLayoutHelperAt(nDevice, pDevice); } } void correctScaleFactor(const PDFExportParams& prms, const OdGsDCRect& clipBox, const OdGeBoundBlock3d& extents, OdDbBaseDatabasePE* pDbPE) { OdRxObjectPtr pLayout = pDbPE->currentLayout(prms.database()); OdDbBaseLayoutPEPtr pLayoutPE(pLayout); if(!pLayoutPE->isModelLayout(pLayout) && pLayoutPE->plotType(pLayout) != OdDbBaseLayoutPE::kExtents) { //printable width and height in mm are // clipBox.m_max - clipBox.m_min kMMPerInch // ------------------------------ then * ----------- => // prms.getGeomDPI() / 72. 72. double printableH = ((double)clipBox.m_max.y - (double)clipBox.m_min.y) * kMmPerInch / (prms.getGeomDPI()); double printableW = ((double)clipBox.m_max.x - (double)clipBox.m_min.x) * kMmPerInch / (prms.getGeomDPI()); double dRealWorldUnits = 1.; double dDrawingUnits = odmax(fabs(extents.maxPoint().x - extents.minPoint().x) / printableW, fabs(extents.maxPoint().y - extents.minPoint().y) / printableH); if(pLayoutPE->plotPaperUnits(pLayout) == OdDbBaseLayoutPE::kInches) dDrawingUnits *= kMmPerInch; //double oldScale; //pLayoutPE->getStdScale(pLayout, oldScale); OdDbSetBasePlotSettingsPEPtr setPsPE(pLayout); if(pLayoutPE->useStandardScale(pLayout)) { double scale = dRealWorldUnits / dDrawingUnits; setPsPE->setScaleFactor(pLayout, scale); } else setPsPE->setPrintScale(pLayout, dRealWorldUnits, dDrawingUnits); } } OdGsDevicePtr CPdfExportImplBase::setupPdfRenderDevice(const PDFExportParams& prms, OdDbBaseDatabasePE* pDbPE, OdGiDefaultContext* pCtx, OdGsDevice& renderDevice, bool bZ2E, OdUInt32 extentsFlag, OdDbStub* objectId, const OdGsDCRect& clipBox, const OdGeBoundBlock3d& extents, bool bIncludeOffLayers) { renderDevice.setBackgroundColor(prms.background()); renderDevice.setLogicalPalette(prms.palette(), 256); OdGsDevicePtr pDevice; if(objectId) pDevice = pDbPE->setupLayoutView(&renderDevice, pCtx, objectId); else pDevice = pDbPE->setupActiveLayoutViews(&renderDevice, pCtx); if( bIncludeOffLayers ) { for (OdInt32 i = 0; i < pDevice->numViews(); i++) { OdGsView* pGsView = pDevice->viewAt(i); OdGsViewImpl* pGsViewImpl = 0; if (pGsView) { pGsViewImpl = OdGsViewImpl::safeCast(pGsView); if (pGsViewImpl) pGsViewImpl->setShowFrozenLayers(true); } } } setLineweightToDcScale(*pDevice, prms.getGeomDPI() / kMmPerInch * 0.01); if(!objectId && !bZ2E) { OdGsDCRect tmpBox = clipBox; pDbPE->applyLayoutSettings(tmpBox/*clipBox*/, pDevice, prms.database(), extentsFlag, prms.getGeomDPI()); } else if(!objectId && bZ2E) { extentsFlag |= OdDbBaseDatabasePE::kUseGivenExtents; OdGeBoundBlock3d ext(extents); pDbPE->zoomToExtents(clipBox, pDevice, prms.database(), ext, extentsFlag, 0);//Zero in first bit means the ExactExtents is true //for views, rendered with GsDevice, the scale factor is calculated from the page params, which can be far from the zoom to extents, //so we need to recalculate it here to get the correct lineweights correctScaleFactor(prms, clipBox, extents, pDbPE); } return pDevice; } void CPdfExportImplBase::DatabasesHolder::startDbTransaction(OdDbBaseDatabase* pDb, bool bSaveGsModel) { _mmap::iterator it = m_data.find(pDb); if(it == m_data.end()) { OdDbBaseDatabasePEPtr(pDb)->startTransaction(pDb); m_data[pDb] = SavedGsModelData(bSaveGsModel ? OdGiDrawable::cast(pDb) : OdGiDrawablePtr()); } } void CPdfExportImplBase::DatabasesHolder::saveGsModel(OdGiDrawable* pDbAsDrawable) { _mmap::iterator it = m_data.find(pDbAsDrawable); if(it == m_data.end()) throw OdError(eInvalidKey); if(!it->second.isValid()) it->second = SavedGsModelData(pDbAsDrawable); } void CPdfExportImplBase::DatabasesHolder::abortTransaction(OdDbBaseDatabase* pDb) { _mmap::iterator it = m_data.find(pDb); if(it == m_data.end()) throw OdError(eInvalidKey); try { OdDbBaseDatabasePEPtr(it->first)->abortTransaction(it->first); } catch(...) { //do nothing, it is just workaround for CORE-18455 till startUndo/undo in pdf export is refactored } if(it->second.isValid()) it->second.restore((OdGiDrawable*)it->first); m_data.erase(it); } void CPdfExportImplBase::DatabasesHolder::abortTransactions() { for(; !m_data.empty();) { _mmap::iterator it = m_data.begin(); try { OdDbBaseDatabasePEPtr(it->first)->abortTransaction(it->first); } catch (...) { //do nothing, it is just workaround for CORE-18455 till startUndo/undo in pdf export is refactored } if(it->second.isValid()) it->second.restore((OdGiDrawable*)it->first); m_data.erase(it); } } static double layoutScaleFactor(const OdRxObjectPtr& pLayout) { OdDbBaseLayoutPEPtr pLayoutPE(pLayout); double layoutScale = 1.; if(pLayoutPE->useStandardScale(pLayout)) pLayoutPE->getStdScale(pLayout, layoutScale); else { double numerator, denominator; pLayoutPE->getCustomPrintScale(pLayout, numerator, denominator); layoutScale = numerator / denominator; } if(OdZero(layoutScale)) layoutScale = 1.; else if(OdNegative(layoutScale)) layoutScale = -layoutScale; return layoutScale; } void CPdfExportImplBase::setupPdfLayout(PdfExportParamsHolder& paramsHolder, OdGsPageParams& pPageParams, OdGsDCRect& clipBox, OdGeBoundBlock3d& plotExtents, OdGiDefaultContextPtr pCtx, PDF2dExportDevice* pDevicePdf, OdDbStub* objectId /*= 0*/) { const PDFExportParams& prms = paramsHolder.getParams(); OdDbBaseDatabasePtr pDb = prms.database(); OdDbBaseDatabasePEPtr pDbPE(pDb); OdUInt32 extentsFlag = 0; SETBIT(extentsFlag, OdDbBaseDatabasePE::kExactExtents, !GETBIT(prms.m_reserved1, 1)); SETBIT(extentsFlag, OdDbBaseDatabasePE::kUseViewExtents, prms.useViewExtents()); SETBIT(extentsFlag, OdDbBaseDatabasePE::kUseGivenView, true); //use PdfExportView to calculate extents const bool bIncludeOffLayers = GETBIT(prms.exportFlags(), PDFExportParams::kIncludeOffLayers); SETBIT(extentsFlag, OdDbBaseDatabasePE::kIncludeOffLayers, bIncludeOffLayers); //use PdfExportView to calculate extents pPageParams.scale((double)prms.getGeomDPI() / 72.); pPageParams.set(OdRoundToLong(pPageParams.getPaperWidth()), OdRoundToLong(pPageParams.getPaperHeight()), int(pPageParams.getLeftMargin()), int(pPageParams.getRightMargin()), int(pPageParams.getTopMargin()), int(pPageParams.getBottomMargin())); clipBox = OdGsDCRect(0, long(pPageParams.getPaperWidth()), 0, long(pPageParams.getPaperHeight())); pDevicePdf->setPaperBox(clipBox); OdGsModel* pModel = NULL; OdPdfExportPEPtr pdfExportPE = OdPdfExport::desc()->getX(OdPdfExportPE::desc()); if (GETBIT(prms.exportFlags(), PDFExportParams::kZoomToExtentsMode) == 0) //!Z2E mode { m_pDevice->onSize(clipBox); pDbPE->applyLayoutSettings(clipBox, m_pDevice, pDb, extentsFlag, prms.getGeomDPI()); pPageParams.set(pPageParams.getPaperWidth(), pPageParams.getPaperHeight(), clipBox.m_min.x, pPageParams.getPaperWidth() - clipBox.m_max.x, pPageParams.getPaperHeight() - clipBox.m_max.y, clipBox.m_min.y); // Apply clip region to screen OdGePoint2dArray clipPoints; clipPoints.push_back(OdGePoint2d(clipBox.m_min.x, clipBox.m_max.y)); clipPoints.push_back(OdGePoint2d(clipBox.m_min.x, clipBox.m_min.y)); clipPoints.push_back(OdGePoint2d(clipBox.m_max.x, clipBox.m_min.y)); clipPoints.push_back(OdGePoint2d(clipBox.m_max.x, clipBox.m_max.y)); pDevicePdf->m_clipPoints = clipPoints; if (!pdfExportPE.isNull()) { OdGiDrawablePtrArray aDrw; pdfExportPE->createAuxDrawables(*m_pDevice, aDrw); pdfExportPE->addDrawables(aDrw, m_pDevice, pModel); } } else //Z2E mode { // temporary enable Frozen layers to calculate valid extents (#16918) clipBox = OdGsDCRect(long(pPageParams.getLeftMargin()), long(pPageParams.getPaperWidth() - pPageParams.getRightMargin()), long(pPageParams.getBottomMargin()), long(pPageParams.getPaperHeight() - pPageParams.getTopMargin())); pDbPE->zoomToExtents(clipBox, m_pDevice, pDb, plotExtents, extentsFlag, objectId);//Zero in first bit means the ExactExtents is true OdRxObjectPtr pLayout = pDbPE->currentLayout(pDb); OdDbBaseLayoutPEPtr pLayoutPE(pLayout); if(pLayoutPE->printLineweights(pLayout)) { double lwToDcScale = (double)prms.getGeomDPI() / kMmPerInch * 0.01; if(pLayoutPE->scaleLineweights(pLayout)) lwToDcScale *= layoutScaleFactor(pLayout); pDevicePdf->setLwToDcScale(lwToDcScale); } if (!pdfExportPE.isNull()) { OdGiDrawablePtrArray aDrw; pdfExportPE->createAuxDrawables(*m_pDevice, aDrw); pdfExportPE->addDrawables(aDrw, m_pDevice, pModel); } } setupPdfRenderDevices(prms, pCtx, *pDevicePdf, objectId, clipBox, plotExtents, bIncludeOffLayers); } bool canUseGsCache(const PDFExportParams &pParams); PDFResultEx CPdfExportImplBase::base_run(PdfExportParamsHolder& paramsHolder, bool isExport2XObj) { PDFExportParams& prms = paramsHolder.getParams(); const bool bIncludeOffLayers = GETBIT(prms.exportFlags(), PDFExportParams::kIncludeOffLayers); OdUInt32 extentsFlag = 0; SETBIT(extentsFlag, OdDbBaseDatabasePE::kExactExtents, !GETBIT(prms.m_reserved1, 1)); SETBIT(extentsFlag, OdDbBaseDatabasePE::kUseViewExtents, prms.useViewExtents()); OdUInt32 nLayoutCount = prms.layouts().size(); if(!nLayoutCount) //layouts can be empty in case of export the active layout of only one drawing nLayoutCount = 1; PDFDocument& PDFDoc = paramsHolder.document(); PDFPageNodeDictionaryPtr pPageTree(PDFDoc.Root()->getPages()); OdDbStub* objectId = 0; bool bDwgPaletteNeeded = false; OdArray palette_array; DbLayout2PagePtr pDbLayout2Page; if(GETBIT(prms.exportFlags(), PDFExportParams::kExportHyperlinks)) pDbLayout2Page = new DbLayout2Page(paramsHolder); PDFResultEx res = startTransactions(prms); if(res != exOk) return res; OdDbToPdfWrapperIfacePtr pDbWrapper; for (OdUInt32 nPageIndx = 0; nPageIndx < nLayoutCount; ++nPageIndx) { OdGiDefaultContextPtr pCtx; OdDbBaseDatabasePtr pDb; if(prms.databases().size()) { pDbWrapper = dynamic_cast(prms.databases()[nPageIndx].get()); if(!pDbWrapper.isNull()) { pDb = pDbWrapper->getDatabase(); pDbWrapper->startDatabaseHandling(); } else pDb = prms.databases()[nPageIndx]; prms.setDatabase(pDb); } else pDb = prms.database(); ODA_ASSERT(pDb); OdDbBaseDatabasePEPtr pDbPE(pDb); PageProcessingCallback callback(pDb, prms, nPageIndx); if(!callback.isValidPage()) { if(prms.stopOnError()) return exCannotRestorePaperFromLayout; continue; } if(prms.layouts().isEmpty()) { OdRxObjectPtr activeLayout = pDbPE->currentLayout(pDb); prms.addLayout(OdDbBaseLayoutPEPtr(activeLayout)->name(activeLayout)); if(prms.pageParams().isEmpty()) { OdGsPageParams params; paramsHolder.getPageParamsFromLayout(activeLayout, params); prms.pageParams().push_back(params); } } else { // layout name validation OdRxObjectPtr pLayout = pDbPE->getLayout(pDb, prms.layouts()[nPageIndx]); if(pLayout.isNull()) { if(!pDbWrapper.isNull()) pDbWrapper->endDatabaseHandling(exLayoutNotFound); prms.setDatabase(0); if(prms.stopOnError()) return exLayoutNotFound; else continue; } } if(GETBIT(prms.exportFlags(), PDFExportParams::kZoomToExtentsMode)) { OdUInt32 nPages = prms.pageParams().size(); if(!nPages && nLayoutCount == 1) { OdRxObjectPtr activeLayout = pDbPE->currentLayout(pDb); OdGsPageParams params; paramsHolder.getPageParamsFromLayout(activeLayout, params); prms.pageParams().push_back(params); } if(nPages != 1 && nLayoutCount != nPages) { if(!pDbWrapper.isNull()) pDbWrapper->endDatabaseHandling(exLayoutNotFound); return exWrongNumberOfPages; } } else { OdRxObjectPtr pLayout = pDbPE->getLayout(pDb, prms.layouts()[nPageIndx]); if(pLayout.isNull() || paramsHolder.getPageParamsFromLayout(pLayout, prms.pageParams()[nPageIndx]) != exOk) { if(!pDbWrapper.isNull()) pDbWrapper->endDatabaseHandling(exCannotRestorePaperFromLayout); prms.setDatabase(0); if(prms.stopOnError()) return pLayout.isNull() ? exLayoutNotFound : exCannotRestorePaperFromLayout; else continue; } } prms.pageParams()[nPageIndx].scale(MM2INCH72(1.)); //Check PDF page size limits if((prms.version() < OdPDF::kPDFv2_0 || prms.archived() > PDFExportDocumentParams::kPDFA_None) && (prms.pageParams()[nPageIndx].getPaperWidth() > 14400 || prms.pageParams()[nPageIndx].getPaperHeight() > 14400)) { if(!pDbWrapper.isNull()) pDbWrapper->endDatabaseHandling(exInvalidPageParams); prms.setDatabase(0); if(prms.stopOnError()) return exInvalidPageParams; else continue; } ////////////////////////////////////////////////////////////////////////// try { pDbPE->setCurrentLayout(pDb, prms.layouts()[nPageIndx]); } catch (...) { if(!pDbWrapper.isNull()) pDbWrapper->endDatabaseHandling(exCannotRestorePaperFromLayout); prms.setDatabase(0); if(prms.stopOnError()) return exCannotRestorePaperFromLayout; else continue; } ////////////////////////////////////////////////////////////////////////// OdPdfExportPEPtr pdfExportPE = OdPdfExport::desc()->getX(OdPdfExportPE::desc()); if (!pdfExportPE.isNull()) pCtx = pdfExportPE->createGiContext(pDb); ////////////////////////////////////////////////////////////////////////// if(!pCtx.get()) { if(!prms.getSelectionSetsArray().size()) pCtx = pDbPE->createGiContext(pDb); else { ODA_ASSERT(prms.getSelectionSetsArray().size() == nLayoutCount); const OdSelectionSetPtr& pSSet = prms.getSelectionSetsArray().at(nPageIndx); if(!pSSet.isNull() && pSSet->numEntities()) { pCtx = pDbPE->createFilteredGiContextForExport(pDb, prms.getSelectionSetsArray().at(nPageIndx)); prms.setUseViewExtents(true); //to avoid export unselected viewports } else pCtx = pDbPE->createGiContext(pDb); } } if (!pdfExportPE.isNull()) pdfExportPE->evaluateFields(pDb); else pDbPE->evaluateFields(pDb, 0x04/*OdDbField::kPlot*/); OdGsPageParams& pPageParams = prms.pageParams()[nPageIndx]; if (!isExport2XObj) { PDFArrayPtr pPages(pPageTree->Find(("Kids"))); PDFPageDictionaryPtr pCurPage = pPages->getAt(nPageIndx); PDFRectanglePtr pRect(PDFRectangle::createObject(PDFDoc)); pRect->set(0, 0, OdInt32(OdRound(pPageParams.getPaperWidth())), OdInt32(OdRound(pPageParams.getPaperHeight()))); pCurPage->setMediaBox(pRect); paramsHolder.setCurrentPage(pCurPage); paramsHolder.setContentCommands(PDFContentStreamPtr(pCurPage->getContents()->last())); } OdGsDevicePtr pDevice = PDF2dExportDevice::createObject(); PDF2dExportDevice* pDevicePdf = (PDF2dExportDevice*)pDevice.get(); pDevicePdf->eraseAllViews(); pDevicePdf->setParams(¶msHolder); //set special context for pdf device pDevicePdf->setDbLayoutToPage(pDbLayout2Page); pCtx->setPlotGeneration(true); // #UpgradePRC: pCtx->setPlotGeneration(prms.getPRCMode() == PDFExportParams::kDisabled); pDbPE->loadPlotstyleTableForActiveLayout(pCtx, pDb); if (canUseGsCache(prms)) { pCtx->enableGsModel(true); pDevicePdf->enableBlockCachSupport(true); pDevicePdf->setSupportParallelVect(paramsHolder.getParams().isParallelVectorization()); pDevicePdf->setCurrentPdfPageNum(nPageIndx); } if (nPageIndx > 0) { if (!prms.layouts()[nPageIndx].compare(prms.layouts()[nPageIndx - 1])) //the same layout as previous objectId = pDbPE->getNextViewForActiveLayout(pCtx, objectId); else objectId = 0; } if ((NULL == prms.palette()) && (0 == nPageIndx)) { // set palette if it is not init. ODCOLORREF Bgr = ODRGBA(ODGETRED(prms.background()), ODGETGREEN(prms.background()), ODGETBLUE(prms.background()), 255); pDbPE->setupPalette(pDevicePdf, pCtx, objectId, Bgr); int num_color; const ODCOLORREF* refColors = pDevicePdf->getLogicalPalette(num_color); if (256 != num_color) throw OdError(::eBadColorIndex); palette_array.insert(palette_array.begin(), refColors, refColors + num_color); prms.setPalette(palette_array.asArrayPtr()); } else { pCtx->setPaletteBackground((ODCOLORREF)(prms.background())); pDevicePdf->setLogicalPalette(prms.palette(), 256); } pDevicePdf->setBackgroundColor(prms.background()); if (!objectId) { m_pDevice = pDbPE->setupActiveLayoutViews(pDevicePdf, pCtx); objectId = pDbPE->getNextViewForActiveLayout(pCtx, objectId); } else { m_pDevice = pDbPE->setupLayoutView(pDevicePdf, pCtx, objectId); } bool bEnableLayers = GETBIT(prms.exportFlags(), PDFExportParams::kEnableLayers); bool bExportOffLayers = GETBIT(prms.exportFlags(), PDFExportParams::kIncludeOffLayers); if(bEnableLayers) { if(bExportOffLayers) pDbPE->loadXrefs(pDb); //To correct off/frozen layers processing, it is necessary to load Xrefs paramsHolder.prepareLayers(pDb, pCtx); pDevicePdf->setFrozenLayers(paramsHolder.getFrozenLayers()); } if (!pdfExportPE.isNull()) pdfExportPE->filterDrawables(*m_pDevice); // !prms.enablePRC will disable rendering of shaded viewports as bitmap pDevicePdf->setRenderDevice(prms.getPRCMode() == PDFExportParams::kDisabled);//!m_Params.enablePRC); applyLineweightToDcScale(prms); OdGsDCRect pageSize(0, long(pPageParams.getPaperWidth()), 0, long(pPageParams.getPaperHeight())); OdGsDCRect clipBox(0, long(pPageParams.getPaperWidth()), 0, long(pPageParams.getPaperHeight())); OdGeBoundBlock3d plotExtents; try { setupPdfLayout(paramsHolder, pPageParams, clipBox, plotExtents, pCtx, pDevicePdf, objectId); } catch (OdError&) { if(!pDbWrapper.isNull()) { m_pDevice->eraseAllViews(); m_pDevice = NULL; pDbWrapper->endDatabaseHandling(exCannotOpenOverallVport); } prms.setDatabase(0); if(prms.stopOnError()) return exCannotOpenOverallVport; else continue; } if(!pdfExportPE.isNull()) { for(int i = pDevicePdf->numRenderDevices(); i--; ) { if(OdGsDevice* pDevice = pDevicePdf->renderLayoutHelperAt(i)) pdfExportPE->filterDrawables(*pDevice); } } m_pDevice->update(0); if GETBIT(prms.exportFlags(), PDFExportParams::kMeasuring) { if(prms.measuringType() == PDFExportParams::kGEO) setGeoSpatialMeasuringViewport(paramsHolder); else setMeasuringViewport(paramsHolder); } if (pDevicePdf->isDWGPaletteNeeded()) bDwgPaletteNeeded = true; OdString layoutName; bool bSetLayoutName = true; if(!prms.layoutNames().isEmpty()) { layoutName = prms.layoutNames().getAt(nPageIndx); bSetLayoutName = false; } if(prms.bookmarksEnabled()) { OdStringArray bookmark_names; OdGePoint3dArray bookmark_points; OdStringArray& names = (isExport2XObj && NULL != paramsHolder.getBookmarkNames()) ? *paramsHolder.getBookmarkNames() : bookmark_names; OdGePoint3dArray& points = (isExport2XObj && NULL != paramsHolder.getBookmarksPoints()) ? *paramsHolder.getBookmarksPoints() : bookmark_points; pDbPE->putNamedViewInfo(pDb, pDbPE->currentLayoutId(pDb), names, points, m_pDevice); if(bSetLayoutName) layoutName = prms.layouts()[nPageIndx]; if (prms.layouts().size() > 1) //maybe !prms.databases().isEmpty() { OdString dbName = pDbPE->getFilename(pDb); dbName = dbName.left(dbName.reverseFind('.')); dbName = dbName.right(dbName.getLength() - dbName.reverseFind(pathChar) - 1); if(bSetLayoutName) layoutName = dbName + L" - " + layoutName; for (OdUInt32 i = 0; i < names.size(); i++) names[i] = dbName + L" - " + names[i]; } if (!isExport2XObj) { for (OdUInt32 i = 0; i < points.size(); i++) { if (points[i].x < 0) points[i].x = 0; if (points[i].y < 0) points[i].y = 0; points[i].x *= (72. / (double)prms.getGeomDPI()); points[i].y *= (72. / (double)prms.getGeomDPI()); if(points[i].x > pageSize.m_max.x) points[i].x = pageSize.m_max.x; if(points[i].y > pageSize.m_max.y) points[i].y = pageSize.m_max.y; } TD_PDF_HELPER_FUNCS::UpdateBookmarksTree(PDFDoc, paramsHolder.CurrentPage(), layoutName, &names, &points); } } //set thumbnail name if present if(!prms.layoutNames().isEmpty()) TD_PDF_HELPER_FUNCS::UpdateThumbnails(PDFDoc, paramsHolder.CurrentPage(), layoutName, !prms.bookmarksEnabled()); if (!isExport2XObj && prms.watermarks().length()) { //const OdGsDCRect pageSize(0, pPageParams.getPaperWidth(), 0, pPageParams.getPaperHeight()); //TODO: add option to use clip box to place watermarks for(OdUInt16 i = 0; i < prms.watermarks().length(); i++) { const Watermark wm = prms.watermarks().at(i); if (nPageIndx == wm.pageIndex || wm.pageIndex == -1) PDFAUX::CreateWatermark(wm, /*clipBox*/pageSize, PDFDoc, paramsHolder.CurrentPage(), pDb, prms, m_FontOptimizer); } } pDevicePdf->setLwToDcScale(0.); //m_dbHolder.abortTransaction(pDb); if(!pDbWrapper.isNull()) { //erase export device in case of database will be released in endDatabaseHandling() m_pDevice->eraseAllViews(); m_pDevice = NULL; //release will be called when nullptr is assigned pDbWrapper->endDatabaseHandling(exOk); } }//for(OdUInt32 nPageIndx = 0; nPageIndx < nLayoutCount; ++nPageIndx) //put indexed Dwg palette if (bDwgPaletteNeeded) PDFAUX::createIndexedDWGPalette(prms.palette(), 256, PDFDoc); if (0 != palette_array.size()) prms.setPalette(NULL); return ::exOk; } void CPdfExportImplBase::setGeoSpatialMeasuringViewport(PdfExportParamsHolder& paramsHolder) { const PDFExportParams& prms = paramsHolder.getParams(); OdDbBaseDatabasePtr pDb = prms.database(); OdString coordSys; int coordSysType = 0; int epsgCode = 0; for(int i = 0; i < m_pDevice->numViews(); i++) { OdGsViewImpl* pDeviceView = OdGsViewImpl::cast(m_pDevice->viewAt(i)); if(!pDeviceView) continue; OdRxObjectPtr pGeoData = OdDbBaseDatabasePEPtr(pDb)->getGeoData(pDb, m_pDevice, pDeviceView); if(pGeoData.isNull()) continue; if(coordSys.isEmpty()) { if(OdDbBaseGeoDataExportPEPtr(pGeoData)->getGeoDataParams(pDb, coordSys, coordSysType, epsgCode) != OdResult::eOk || coordSys.isEmpty()) return; } OdGePoint2dArray geoExtents, viewportClip; OdGePoint2d ptMin, ptMax; pDeviceView->screenRect(ptMin, ptMax); OdGeMatrix3d matO2D = pDeviceView->objectToDeviceMatrix(); OdGeMatrix3d matD2O = matO2D; matD2O.invert(); OdGePoint3d ptBuf; //convert viewport coordinates into drawing coordinates ptBuf.x = ptMin.x; ptBuf.y = ptMin.y; ptBuf.transformBy(matD2O); ptMin = ptBuf.convert2d(); ptBuf.x = ptMax.x; ptBuf.y = ptMax.y; ptBuf.transformBy(matD2O); ptMax = ptBuf.convert2d(); viewportClip.push_back(OdGePoint2d(ptMin.x, ptMin.y)); viewportClip.push_back(OdGePoint2d(ptMin.x, ptMax.y)); viewportClip.push_back(OdGePoint2d(ptMax.x, ptMax.y)); viewportClip.push_back(OdGePoint2d(ptMax.x, ptMin.y)); if(OdDbBaseGeoDataExportPEPtr(pGeoData)->getGeoExtents(pDb, geoExtents, viewportClip) != OdResult::eOk) continue; //convert coordinates back to viewport coordinates for(OdUInt32 i = 0; i < viewportClip.size(); ++i) { ptBuf.x = viewportClip[i].x; ptBuf.y = viewportClip[i].y; ptBuf.transformBy(matO2D); ptBuf.scaleBy((72. / (double)prms.getGeomDPI())); viewportClip[i] = ptBuf.convert2d(); } PDFAUX::createMeasuringViewPortGEO(paramsHolder.document(), paramsHolder.CurrentPage(), coordSys, coordSysType, epsgCode, geoExtents, viewportClip); } } void CPdfExportImplBase::setMeasuringViewport(PdfExportParamsHolder& paramsHolder) { const double iPdfScale = (72. / (double)paramsHolder.getParams().getGeomDPI()); const int nViews = m_pDevice->numViews(); OdArray vpRectArray; for(int i = 0; i < nViews; i++) { OdGsViewImpl* pDeviceView = OdGsViewImpl::cast(m_pDevice->viewAt(i)); if(!pDeviceView) continue; OdGePoint2d ptMin, ptMax; pDeviceView->screenRect(ptMin, ptMax); ptMin.scaleBy(iPdfScale); ptMax.scaleBy(iPdfScale); const OdGsDCRect clipBox((long)ptMin.x, (long)ptMax.x, (long)ptMin.y, (long)ptMax.y); const double iScale = pDeviceView->objectToDeviceMatrix().invert().scale() / iPdfScale; if(!vpRectArray.contains(clipBox)) { PDFAUX::createMeasuringViewPort(clipBox, paramsHolder.document(), paramsHolder.CurrentPage(), iScale); vpRectArray.push_back(clipBox); } } } PDFResultEx CPdfExportImplBase::startTransactions(const PDFExportParams &pParams) { const bool bSaveGsModel = false; OdRxObjectPtrArray paramDBs = pParams.databases(); for(OdUInt32 i = 0; i < paramDBs.size(); i++) { if(paramDBs[i].isNull()) return exNullDatabase; OdDbToPdfWrapperIfacePtr pDbWrapper = dynamic_cast(paramDBs[i].get()); if(!pDbWrapper.isNull()) return exOk; m_dbHolder.startDbTransaction(paramDBs[i], bSaveGsModel); } if(!paramDBs.size()) m_dbHolder.startDbTransaction(pParams.database(), bSaveGsModel); return ::exOk; } }