======================== Exporting a PDF document ======================== In this chapter, we discuss how to create a PDF document from our HOOPS Visualize application. The aim to is create the document shown below. It contains some information about the model, an embedded 3D model and of course a table. .. image:: images/publish_example.png We will introduce HOOPS Publish and explain how to use it from HOOPS Visualize. For an introduction to HOOPS Publish in the context of HOOPS Visualize, please refer to `this section `_ of the HOOPS Visualize Documentation. For a more in depth introduction to HOOPS Publish itself, please refer to the HOOPS Publish document which can be found `here `_. Adding HOOPS Publish to the project ----------------------------------- By default, the base MFC sandbox doesn't include HOOPS Publish. You will need to take three steps to ensure it is included in the project: #. Add ``USING_PUBLISH`` to the preprocessor definitions in the C/C++ section of the project settings #. Add *hps_sprk_publish.lib* to the Linker Additional Dependencies section of the project setting #. Ensure that you have installed a copy of the 3rd-party utility TableToPDF (see below). This is essential for the table export to work. TableToPDF ---------- TableToPDF is a utility that creates PDF tables from HTML. The table implementation uses an add-on to HOOPS Publish (TableToPDF) which is provided for free by Tech Soft 3D. The add-on is using components that are licensed under GNU LGPL terms. Consequently, the usage of tables using HOOPS Publish add-on requires your application to comply with LGPL requirements. TableToPDF can be downloaded at http://developer.techsoft3d.com/add-ons/tabletopdf/. The deployment process is simple and just requires to copy the provided DLLs in HOOPS Publish binaries folder. Creating a report builder class ------------------------------- We begin by defining a class to encapsulate the PDF report building functionality, which we'll call IFCReportBuilder. This class will take an ``IFCQuantity`` object and generate a PDF report based on that. The full class declaration is shown below. In addition to storing the parameters we pass in with the member functions, we have also declared some internal string variables which are used during the report building phase. .. literalinclude:: /source/IFCReportBuilder.h :language: c :start-after: //! [report_builder] :end-before: //! [report_builder] Implementation overview ----------------------- Before we get into the details, let's first discuss what our PDF document contains and which HOOPS Publish object types we will be working with. At the highest level, we will be creating a PDF Document. For this simple example, we just use a single page. The PDF page contains a page title, information about the model, a 3D view containing the model, and a table of quantities. In summary, we will be working with the following objects: * PDF Document * PDF Page * Text Object * 3D Annotation * Table In the context of HOOPS Visualize and the Component classes, these are defined by the following kits: * ``HPS::Publish::AnnotationKit`` * ``HPS::Publish::PageKit`` * ``HPS::Publish::DocumentKit`` * ``HPS::Publish::TableKit`` * ``HPS::Publish::TextKit`` For each, there is also a key to access the object. For instance, in the case of a Document, ``HPS::Publish::DocumentKey``. Defining a page and its contents -------------------------------- Using HOOPS Publish, you typically define the contents of a PDF document using kits and create the objects when adding them to a page. To begin, lets set a layout for the page, then we can position objects in the page with respect to that. .. literalinclude:: /source/IFCReportBuilder.cpp :language: c :start-after: //! [page_format] :end-before: //! [page_format] Creating a text object ...................... The simplest object to create is a plain text label. We use this for the page title as shown below: .. literalinclude:: /source/IFCReportBuilder.cpp :language: c :start-after: //! [text_label] :end-before: //! [text_label] Additionally, using the CAD model we passed in, let's display its name. .. literalinclude:: /source/IFCReportBuilder.cpp :language: c :start-after: //! [model_name] :end-before: //! [model_name] As you can see, the ``textKit`` allows us to control various attributes of the text, such as the font, color, and size. One thing to be aware of is the page origin is located at the lower left side of the page. Inserting a 3D model .................... Inserting a 3D model into the page, using default settings, is also simple: .. literalinclude:: /source/IFCReportBuilder.cpp :language: c :start-after: //! [insert_model] :end-before: //! [insert_model] This code will create an embedded 3D object in the PDF page, encoded as a PRC data object. This is the same data type used by HOOPS Exchange. In this case, we select tessellation only. In fact, we really only need to set the source, that is, the CAD model. However, it is possible to control more aspects of how we want to display such as the initial camera and poster image. The latter is used when the 3D object is not activated or the document printed. Please refer to this section of the documentation for more details: https://docs.techsoft3d.com/hps/latest/build/prog_guide/0905_publish_integration.html. Inserting a table ................. Creating the table is the most complex part of our tutorial example. We're going to create a fixed position plain text table, although its possible to create tables with interactive fields and also interactive scrolling tables. To begin, here is the code which inserts the table into the page: .. literalinclude:: /source/IFCReportBuilder.cpp :language: c :start-after: //! [add_table] :end-before: //! [add_table] The parameters to the table are two strings - one representing the table content, and the other representing the table style. We're using HTML to define the contents and the layout of the table. This is where the 3rd-party library TableToPDF comes in. This utility takes the HTML and creates a PDF object. Therefore, the main work for us to do is to create the HTML and CSS strings which define the table. Building the report ------------------- To return to our class definition, we defined three functions. Two simply save the parameters to the report. The function ``BuildReport`` is where most work takes place. .. literalinclude:: /source/IFCReportBuilder.cpp :language: c :start-after: //! [BuildReport] :end-before: //! [BuildReport] As can be seen, this function assembles an HTML string representing the table contents. It in turns calls the following functions: .. literalinclude:: /source/IFCReportBuilder.cpp :language: c :start-after: //! [table_contents] :end-before: //! [table_contents] Once the string is assembled, it is used as a parameter to the function ``CreatePDF``. The full source for ``CreatePDF`` is shown here: .. literalinclude:: /source/IFCReportBuilder.cpp :language: c :start-after: //! [CreatePDF] :end-before: //! [CreatePDF] Creating the document --------------------- At the end of ``CreatePDF``, you can see that we create a new document and add the page we defined. Finally, we ask HOOPS Publish to create the PDF file on disk. There are a variety of exceptions which can be thrown by HOOPS Publish. We trap them here to tidy things up, but then throw the exception to the calling code to handle the UI notifications. CSS creation ............ One thing we didn't cover is how the table layout gets created. For this sample we just create a fixed layout defined called from the class constructor: .. literalinclude:: /source/IFCReportBuilder.cpp :language: c :start-after: //! [InitializeTable] :end-before: //! [InitializeTable] Connecting to the UI -------------------- When we created the quantities dialog, we added a button to create a PDF report. We need to attach an event handler to the button then call the report builder functionality. It is relatively simple code, the majority of which is spent asking for a file path for the report. One thing to note is we trap any exceptions coming from the report builder, and in particular display a message. .. literalinclude:: /source/CComponentQuantitiesDlg.cpp :language: c :start-after: //! [OnBnClickedBtnQuantityReport] :end-before: //! [OnBnClickedBtnQuantityReport]