# PDF report linking

**URL:** <https://forum.inductiveautomation.com/t/pdf-report-linking/18860>\
**Category:** Ignition\
**Created:** [July 17, 2018, 8:59am UTC](https://forum.inductiveautomation.com/t/pdf-report-linking/18860 "2018-07-17T08:59:12Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Dilan](https://avatars.discourse-cdn.com/v4/letter/d/ba8739/32.png) [@Dilan](https://forum.inductiveautomation.com/u/Dilan)\
**Post date:** [July 17, 2018, 8:59am UTC](https://forum.inductiveautomation.com/t/pdf-report-linking/18860/1 "2018-07-17T08:59:12Z")

</div>

Hi all,

I’m not sure if you’ve come across the need to link within a pdf but I have.

My pdf report is over 70 pages due to the nature of the site, and as the report goes out to multiple people I have an index page at the front of my pdf. What I would like to do is on the index page have the pdf generated with links, so they user can click on page 35 and be taken to that page. The other thing is I’d also like to have hyperlinks to email addresses and our website within the pdf. This is as our reports go out to our clients. If any one has done anything similar I’d love to hear about it.

Also I have submitted this as a feature request should anyone else be interested in this.

[https://inductiveautomation.canny.io/ignition-features-and-ideas/p/report-pfd-linking](https://inductiveautomation.canny.io/ignition-features-and-ideas/p/report-pfd-linking)

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [July 18, 2018, 5:32pm UTC](https://forum.inductiveautomation.com/t/pdf-report-linking/18860/2 "2018-07-18T17:32:28Z")

</div>

You completely nerd-sniped me with this topic - I definitely shouldn’t have spent as much time on this as I did. But, this _is_ actually possible with the existing reporting module. We’ll definitely have to see about adding this capability in a better way.  
Basically, the workaround I came up with relies on the fact that objects in reporting can be copied to the clipboard and show up as XML representations of the underlying Java object. So, to use this (extremely janky) workaround:  
0. Paste the script below into the script console and execute it. Nothing will happen - that’s intentional.

1. Copy the desired component (I’ve only really tested text shapes) to the clipboard.
2. Go back to the script console, and in the interactive interpreter, run `addURLToClipboardObject(<someURL>)`. To link to a specific page, use `addURLToClipboardObject("Page:3")`. You can also use `Page:Next` and `Page:Back`.
3. Click back to the reporting workspace, and specifically click into the editor/visible page. Then paste your modified object.

If everything went correctly, the hyperlink should be active on the preview tab:  
 ![](https://us1.discourse-cdn.com/inductiveautomation/original/2X/9/9705888644af4467dabdcc10f00173dd306ece73.png)

And, without further ado, the hacky monstrosity that will do all this. It’s pretty unlikely this will break any existing report, but it may throw all kinds of errors into the console. I would recommend copying your report to a new project, going through this process to add the links, and once you’ve verified it works copy the report back to your original project.

```python
def addURLToClipboardObject(url):
	from java.awt import Toolkit
	from java.awt.datatransfer import DataFlavor, Transferable
	from java.io import ByteArrayInputStream
	from java.lang import String
	import re
	
	class MockReportMillClipboard(Transferable):
		RMDataFlavor = DataFlavor("application/reportmill", "ReportMill Shape Data")
		def __init__ (self, data):
			self.data = String(data).getBytes()
		
		def isDataFlavorSupported(self, flavor):
			return flavor == self.RMDataFlavor
		
		def getTransferData(self, flavor):
			if flavor == self.RMDataFlavor:
				return ByteArrayInputStream(self.data)

		def getTransferDataFlavors(self):
			return self.RMDataFlavor.getTransferDataFlavors()
	        
	clip = Toolkit.getDefaultToolkit().getSystemClipboard()
	
	dataflavor = None
	for df in clip.getAvailableDataFlavors():
		if df.mimeType == 'application/x-java-serialized-object; class=java.lang.String':
			dataflavor = df
			break
	if dataflavor:
		data = clip.getData(dataflavor)
		regex = r"<text(.*)>"
		subst = r'<text\g<1> url="%s">' % url
		result = re.sub(regex, subst, data, re.MULTILINE)
		print "Added URL to clipboard object"
		clip.setContents(MockReportMillClipboard(result), None)

```

---

<div class="post-metadata">

**Author:** ![Dilan](https://avatars.discourse-cdn.com/v4/letter/d/ba8739/32.png) [@Dilan](https://forum.inductiveautomation.com/u/Dilan)\
**Post date:** [July 19, 2018, 12:58pm UTC](https://forum.inductiveautomation.com/t/pdf-report-linking/18860/3 "2018-07-19T12:58:06Z")

</div>

Hello Paul,

Thank you so much for spending time on this, I really do appreciate it. In fact its what’s so great about Ignition that we have this community. I will definitely give this a bash and let you know how I get along. It’s certainly going to make the reporting that much more powerful for us.

---

<div class="post-metadata">

**Author:** ![Dilan](https://avatars.discourse-cdn.com/v4/letter/d/ba8739/32.png) [@Dilan](https://forum.inductiveautomation.com/u/Dilan)\
**Post date:** [July 19, 2018, 1:29pm UTC](https://forum.inductiveautomation.com/t/pdf-report-linking/18860/4 "2018-07-19T13:29:33Z")

</div>

Hello Paul,

This worked like a charm in the report preview and in the report viewer window.

I then realised that my question was not as well defined as I thought, and I do apologise for this. You see the old reports were done in Microsoft Word with a table of contents, and when they were exported to PDF the table of contents was “clickable”. This is what I was after so that when the user generates the report then saved it and emailed it to the client the table of contents still had hyperlinks in it.

I have a button along side my report viewer, and once I use it to save to pdf, the links don’t work once the pdf is saved to the local computer and opened in the adobe pdf viewer.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [July 19, 2018, 3:11pm UTC](https://forum.inductiveautomation.com/t/pdf-report-linking/18860/5 "2018-07-19T15:11:45Z")

</div>

Hmm, that’s interesting - when I was testing this I specifically tried saving the output and was still able to click the links.

EDIT: Looks like there’s a limitation - when the objects get copied to subsequent pages due to table wrapping, they don’t get clickable links in a PDF export, even though they do in the report viewer/preview. Unfortunately, I don’t know if that’s going to be solveable. I was able to put multiple clickable links onto the first page, which do come out clickable when opened using Chrome’s built-in PDF viewer, so they _should_ work in other PDF viewers.

[Linking 7-19-18 08AM.pdf](https://us1.discourse-cdn.com/inductiveautomation/original/2X/9/97b8895de2a856c9ef96b2d057ce2d13ee24e316.pdf) (4.9 KB)

---

<div class="post-metadata">

**Author:** ![Dilan](https://avatars.discourse-cdn.com/v4/letter/d/ba8739/32.png) [@Dilan](https://forum.inductiveautomation.com/u/Dilan)\
**Post date:** [July 20, 2018, 2:36pm UTC](https://forum.inductiveautomation.com/t/pdf-report-linking/18860/6 "2018-07-20T14:36:05Z")

</div>

Hello Paul,

Your document links are working in my Chrome browser as well, so its strange in acrobat its not working, maybe I have a setting somewhere that is causing this. I will play around more with this next week, please do excuse the disjointed responses, as our time zones are far apart. I’ll have more feedback for you next week.

---

<div class="post-metadata">

**Author:** ![Dilan](https://avatars.discourse-cdn.com/v4/letter/d/ba8739/32.png) [@Dilan](https://forum.inductiveautomation.com/u/Dilan)\
**Post date:** [July 27, 2018, 10:54am UTC](https://forum.inductiveautomation.com/t/pdf-report-linking/18860/7 "2018-07-27T10:54:07Z")

</div>

Hello Paul,

Some great news, after playing with the reports a bit more your solution is working on adobe and chrome, I think I must’ve made a mistake somewhere when working between the links. I really can’t thank you enough for your assistance with this.

---

<div class="post-metadata">

**Author:** ![jbrad](https://avatars.discourse-cdn.com/v4/letter/j/ccd318/32.png) [@jbrad](https://forum.inductiveautomation.com/u/jbrad)\
**Post date:** [October 14, 2021, 12:30am UTC](https://forum.inductiveautomation.com/t/pdf-report-linking/18860/8 "2021-10-14T00:30:29Z")

</div>

I'm trying to get this to run using "Page:2" in the arguments but I'm getting the following error in the interpreter. Any ideas?

> \>\>\> addURLToClipboardObject("Page:2")  
> Added URL to clipboard object  
> Traceback (most recent call last):  
> File "", line 1, in   
> File "", line 33, in addURLToClipboardObject  
> NotImplementedError: 'MockReportMillClipboard' object does not implement abstract method 'getTransferDataFlavors' from 'java.awt.datatransfer.Transferable'

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [October 14, 2021, 8:28pm UTC](https://forum.inductiveautomation.com/t/pdf-report-linking/18860/9 "2021-10-14T20:28:00Z")

</div>

> [@jbrad](#):
>
> I’m trying to get this to run using “Page:2” in the arguments but I’m getting the following error in the interpreter. Any ideas?

Hm, it definitely used to work, I'm not sure why that's required now. But I updated the original post to implement that method as well.

---

<div class="post-metadata">

**Author:** ![jbrad](https://avatars.discourse-cdn.com/v4/letter/j/ccd318/32.png) [@jbrad](https://forum.inductiveautomation.com/u/jbrad)\
**Post date:** [October 14, 2021, 10:51pm UTC](https://forum.inductiveautomation.com/t/pdf-report-linking/18860/10 "2021-10-14T22:51:09Z")

</div>

Thanks for the quick response!

I've just tried it again and now the error has changed to:

> Added URL to clipboard object  
> Traceback (most recent call last):  
> File "", line 1, in   
> File "", line 36, in addURLToClipboardObject  
> File "", line 21, in getTransferDataFlavors  
> AttributeError: 'java.awt.datatransfer.DataFlavor' object has no attribute 'getTransferDataFlavors'

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [October 14, 2021, 11:17pm UTC](https://forum.inductiveautomation.com/t/pdf-report-linking/18860/11 "2021-10-14T23:17:55Z")

</div>

Maybe make it

```auto
		def getTransferDataFlavors(self):
			return [self.RMDataFlavor]

```

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [July 1, 2022, 5:29pm UTC](https://forum.inductiveautomation.com/t/pdf-report-linking/18860/12 "2022-07-01T17:29:17Z")

</div>

Good news! In 8.1.19 this will finally be directly possible:

> [@Nightly 8.1 Changelogs - 2022](https://forum.inductiveautomation.com/t/nightly-8-1-changelogs-2022/54636/103):
>
> Weekly Changelog: 8.1.19-b20220630 Visualization 986: Add URL property (back to) reporting components Added the URL property to Reporting components. This allows you to add clickable hyperlinks within the report preview, Vision report viewer, and PDF output reports, including the Perspective report viewer. 5497: Perspective Alarm status table does not apply bound filter on initial load Alarm tables no longer discard incoming changes to filters when actively performing a polling query.

Plus some fixed bugs with link generation that this workaround would never have helped with 🙂

---

<div class="post-metadata">

**Author:** ![dilanjivanji](https://avatars.discourse-cdn.com/v4/letter/d/eb8c5e/32.png) [@dilanjivanji](https://forum.inductiveautomation.com/u/dilanjivanji)\
**Post date:** [July 1, 2022, 7:46pm UTC](https://forum.inductiveautomation.com/t/pdf-report-linking/18860/13 "2022-07-01T19:46:28Z")

</div>

Hello, this is awesome to hear, thank you so much!
