########################
Image and SVG Generation
########################

Image creation overview
=======================

The HOOPS Web Viewer supports the ability to take a snapshot image of the current HOOPS Web Viewer Canvas. The result is an HTMLImageElement which can be displayed directly in in the current browser, or the image data can be extracted and sent back to the web-server.


Example: Creating and displaying a snapshot image
=================================================

To create a snapshot image, call the function :ref:`takeSnapshot()  <api_ref/viewing/classes/Communicator.WebViewer:takesnapshot>` which can be found in the ``Communicator.WebViewer`` class. The :ref:`takeSnapshot()  <api_ref/viewing/classes/Communicator.WebViewer:takesnapshot>` function takes an optional :doc:`Communicator.SnapshotConfig </api_ref/viewing/classes/Communicator.SnapshotConfig>`  which can be used to control the size of the resultant image. The return value of :ref:`takeSnapshot() <api_ref/viewing/classes/Communicator.WebViewer:takesnapshot>` is a Promise that resolves to an ``HTMLImageElement`` containing the created image.

The full HTML and Javascript for this example can be viewed in the Communicator package in the examples folder: *web_viewer/examples/simple_snapshot.html*.

This simple example first creates a snapshot image, then adds the newly created image into the same web-page that contains the HOOPS Web Viewer canvas. First, you'll need an HTML page that creates and starts the HOOPS Web Viewer. For the purpose of this example, it is assumed the HOOPS Web Viewer Canvas is sized to 640x480 pixels. Next, add an empty HTML <div> tag as the last tag within the <body> section of the page, like this:

``<div id="snapshots">``

Next, add a button to the html page and have it call the following function which will generate a snapshot image and display the result. This function first creates the image, then upon it's completion, appends it to the content of our <div> tag. Note that the image is created much smaller than the source canvas by passing the width/height as configuration parameters.

.. literalinclude:: /../../applications/client/docs/SvgExport.ts
	   :start-after: //! [snapshot_create]
	   :end-before: //! [snapshot_create]


Snapshot configuration
======================

The following fields are available to set within the :ref:`Communicator.SnapshotConfig  <api_ref/viewing/classes/Communicator.SnapshotConfig>` class.

**width: <small>number</small>**

Specifies the width of the resulting snapshot image. A value of 0 indicates the canvas width should be used. The default value is 0.

**height: <small>number</small>**

Specifies the height of the resulting snapshot image. A value of 0 indicates the canvas height should be used. The default value is 0.


Extracting the image data
=========================

To extract the image data from the return image element, you can use a temporary HTML Canvas object which acts as an offscreen buffer. First you create the canvas object, then draw the image to it, and finally extract the result from the canvas. The following example code shows how extract the image data as base64 encoded string:

.. raw:: js

	viewer.takeSnapshot().then(function(image) {  
		var canvas = document.createElement("canvas"); 
		canvas.width = image.width; 
		canvas.height = image.height; 
		var ctx = canvas.getContext("2d"); 
		ctx.drawImage(image, 0, 0); 
		var base64Encoded = canvas.toDataURL("image/png"); 
		console.log(base64Encoded); 
	});

The console output will look something like:

``data:image/png;base64,iVBORw0Kggo…``

You can also use the ``canvas.toBlob()`` function to extract the image data as blob, which would be suitable for sending the image back to a server in binary form. For more information on sending blobs, see https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data.


SVG creation overview
=====================

The HOOPS Web Viewer has the ability to create a two-dimensional Scalable Vector Graphics (SVG) representation of the currently displayed scene. The resultant SVG will contain a series of polygons and polylines that when rendered, will look similar to the original three-dimensional view.


SVG features
------------

An important feature of an SVG is its ability to render with high fidelity at varying zoom levels. This is an advantage over bitmapped images, which tend to show pixelated artifacts at high zoom levels.


SVG limitations
---------------

The SVG representations created by the HOOPS Web Viewer have a few limitations. First, there is no shading or lighting in the SVG. Thus, faces of the model will be flat shaded with uniform color based on the color defined for that face. Any textures in the model are ignored.

Another limitation with SVG creation is processing time. Generating an SVG from a three-dimensional view is computationally expensive and does not use the GPU like typical rendering solutions. Very small models may take a few seconds to export, while large models can take minutes.


Example: Creating and displaying an SVG
=======================================

To create an SVG, call the function :ref:`exportToSvg()  <api_ref/viewing/classes/Communicator.WebViewer:exporttosvg>` which can be found in the :doc:`Communicator.WebViewer </api_ref/viewing/classes/Communicator.WebViewer>` class. The :ref:`exportToSvg() <api_ref/viewing/classes/Communicator.WebViewer:exporttosvg>` takes an optional :doc:`Communicator.SvgConfig </api_ref/viewing/classes/Communicator.SvgConfig>` which can be used to control certain aspects of the resultant SVG. The return value of ``exportToSvg()`` is a Promise that resolves to a string containing the created SVG.

The full HTML and Javascript for this example can be viewed in the Communicator package in the examples folder: *web_viewer/examples/svg_display.html*

This simple example first creates an SVG, then renders the result in the same web-page that contains the HOOPS Web Viewer. First, you'll need an HTML page that creates and starts the HOOPS Web Viewer. For the purpose of this example, it is assumed the HOOPS Web Viewer Canvas is sized 640x480 pixels. Next, add an empty HTML <div> tag as the last tag within the <body> section of the page, like this:


``<div id="display-svg" style="width: 640px; height: 480px"></div>``

Next, add a button to the html page and have it call the following function which will generate an SVG and display the result. This function first creates the SVG, then upon its completion, sets the content of our <div> tag to the created SVG string. This works because the SVG creation returns an XML string with a root tag of <svg> that can be directly interpreted and rendered by modern browsers.

.. literalinclude:: /../../applications/client/docs/SvgExport.ts
	   :start-after: //! [svg_create]
	   :end-before: //! [svg_create]
	   
If you'd like to export to a new browser tab, use the following code (requires Pop-Ups to be enabled in the browser):

.. literalinclude:: /../../applications/client/docs/SvgExport.ts
	   :start-after: //! [output_svg_to_window]
	   :end-before: //! [output_svg_to_window]

As in the examples above, the :ref:`exportToSvg()  <api_ref/viewing/classes/Communicator.WebViewer:exporttosvg>` function can be called with no arguments, or you can pass it an :doc:`SvgConfig </api_ref/viewing/classes/Communicator.SvgConfig>` object that contains various settings related to output, styling, etc. For example:

.. literalinclude:: /../../applications/client/docs/SvgExport.ts
	   :start-after: //! [svg_styles]
	   :end-before: //! [svg_styles]


Using the results
=================

The format of SVG is XML, and therefore the string returned by :ref:`exportToSvg  <api_ref/viewing/classes/Communicator.WebViewer:exporttosvg>` will be a well-formed XML string. A typical XML document will begin with a prolog string like:

``<?xml version='1.0' encoding='UTF-8' standalone='no'?>``

Depending on how you intend to use the results, you can specify if this prolog is present. If the result is going to be saved off as a standalone XML file with an ".svg" suffix, then the prolog should be present. If the result is going to be directly rendered in a page like the previous example, then the prolog should be suppressed. The default configuration will include the prolog but it can be suppressed via the configuration parameter.

If you would like the SVG string to be used as a standalone file, you will need to extract from the web-page. A simplistic way to do this would be to simply display the string, say in a simple pop-up, and allow the user to copy-paste it. A more sophisticated approach would be to send it back to the web-server for storage. This can be done with the XMLHttpRequest class, which is detailed https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest. 


SVG configuration
=================

The following fields are available within the :doc:`Communicator.SvgConfig  </api_ref/viewing/classes/Communicator.SvgConfig>` class:

.. csv-table::
	:header: "Field", "Description"
	
	"``linesClipProximityToPlane``: number", "For line clipping, this factor determines how close a line can get to a triangle without getting clipped. Larger values will help small sections that shouldn't get clipped, but larger values may also allow hidden line sections to poke through. Z values are normalized to -32767 to 32767, so this value is relative to that scale. (default: 5.5)"
	"``linesClipZNudgeFactor``: number", "For line clipping, this value will be used to adjust line segment endpoints, bringing closer to the camera for positive values. This is helpful for z-fighting causing small sections of lines to be unintentionally clipped. Z values are normalized to -32767 to 32767, so this value is relative to that scale. (default: 5.5)"
	"``linesCssColor``: string", "CSS compliant color string used to draw lines (default: '#000000')"
	"``linesDrawModelLinesEnabled``: boolean", "Determines if the model lines will be included in the SVG output (default: true)"
	"``linesStrokeWidth``: number", "Determines the output SVG line width for all lines in the model. This is relative to the SVG viewBox settings of -32767 to +32767 in both X and Y directions. (default: 20.0)"
	"``logDiagnostics``: boolean", "Enables diagnostics logging. If running in-browser, this will go to the developer console (default: false)"
	"``logProgress``: boolean", "Enables progress logging. If running in-browser, this will go to the developer console (default: false)"
	"``polygonsForceDrawCssColor``: string",  "If set to a non-empty CSS string value, forces all polygons to be drawn as this color. Example, to force all polygons to be white, use ``PolygonsForceDrawColor='#ffffff'``(default: '')"
	"``silhouettesEnabled``: boolean", "Determines if silhouette lines will be drawn for the model (default: true)"
	"``svgBackgroundCssColor``: string", "If non-empty, an SVG element will be at the root with the given background color. (default: '')"
	"``svgXmlPrologEnabled``: boolean", "If true, the standard XML prolog will be included in the output SVG (default: true)"
	
