<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>PDF &#8211; Xojo Programming Blog</title>
	<atom:link href="https://blog.xojo.com/tag/pdf/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.xojo.com</link>
	<description>Blog about the Xojo programming language and IDE</description>
	<lastBuildDate>Tue, 31 Mar 2026 15:22:37 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>More New Features for Android: MobileChart, MobileColorPicker, MobilePDFViewer &#038; Zip/Unzip</title>
		<link>https://blog.xojo.com/2026/03/31/more-new-features-for-android/</link>
		
		<dc:creator><![CDATA[Paul Lefebvre]]></dc:creator>
		<pubDate>Tue, 31 Mar 2026 15:22:00 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[2026r1]]></category>
		<category><![CDATA[Charts]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[Unzip]]></category>
		<category><![CDATA[Zip]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16035</guid>

					<description><![CDATA[The first release of 2026 brings some notable new features to Xojo’s Android support. You’ll find new charting, color-picking, PDF viewing, and file-zip utilities, plus&#8230;]]></description>
										<content:encoded><![CDATA[
<p>The first release of 2026 brings some notable new features to Xojo’s Android support. You’ll find new charting, color-picking, PDF viewing, and file-zip utilities, plus ongoing improvements to several controls. Here’s a quick tour of what’s new.</p>



<h2 class="wp-block-heading"><strong>MobileChart</strong></h2>



<p>Matching the features available for iOS, <a href="https://documentation.xojo.com/api/user_interface/mobile/mobilechart.html#mobilechart" target="_blank" rel="noreferrer noopener">MobileChart</a> lets you create a wide variety of charts to show in your Android app.</p>



<figure class="wp-block-image size-large is-resized"><img fetchpriority="high" decoding="async" width="483" height="1024" src="https://blog.xojo.com/wp-content/uploads/2026/03/CleanShot-2026-03-24-at-13.19.47@2x-483x1024.png" alt="" class="wp-image-16036" style="width:198px;height:auto" srcset="https://blog.xojo.com/wp-content/uploads/2026/03/CleanShot-2026-03-24-at-13.19.47@2x-483x1024.png 483w, https://blog.xojo.com/wp-content/uploads/2026/03/CleanShot-2026-03-24-at-13.19.47@2x-142x300.png 142w, https://blog.xojo.com/wp-content/uploads/2026/03/CleanShot-2026-03-24-at-13.19.47@2x-768x1628.png 768w, https://blog.xojo.com/wp-content/uploads/2026/03/CleanShot-2026-03-24-at-13.19.47@2x-725x1536.png 725w, https://blog.xojo.com/wp-content/uploads/2026/03/CleanShot-2026-03-24-at-13.19.47@2x.png 918w" sizes="(max-width: 483px) 100vw, 483px" /></figure>



<h2 class="wp-block-heading"><strong>MobileColorPicker</strong></h2>



<p>This new control, <a href="https://documentation.xojo.com/api/user_interface/mobile/mobilecolorpicker.html#mobilecolorpicker" target="_blank" rel="noreferrer noopener">as its name suggests</a>, lets you use the system color picker to select a color.</p>



<figure class="wp-block-image size-large is-resized"><img decoding="async" width="481" height="1024" src="https://blog.xojo.com/wp-content/uploads/2026/03/CleanShot-2026-03-24-at-13.21.46@2x-481x1024.png" alt="" class="wp-image-16038" style="width:202px;height:auto" srcset="https://blog.xojo.com/wp-content/uploads/2026/03/CleanShot-2026-03-24-at-13.21.46@2x-481x1024.png 481w, https://blog.xojo.com/wp-content/uploads/2026/03/CleanShot-2026-03-24-at-13.21.46@2x-141x300.png 141w, https://blog.xojo.com/wp-content/uploads/2026/03/CleanShot-2026-03-24-at-13.21.46@2x-768x1634.png 768w, https://blog.xojo.com/wp-content/uploads/2026/03/CleanShot-2026-03-24-at-13.21.46@2x-722x1536.png 722w, https://blog.xojo.com/wp-content/uploads/2026/03/CleanShot-2026-03-24-at-13.21.46@2x.png 912w" sizes="(max-width: 481px) 100vw, 481px" /></figure>



<h2 class="wp-block-heading"><strong>MobilePDFViewer</strong></h2>



<p>Last year Android added <a href="https://documentation.xojo.com/api/pdf/pdfdocument.html#pdfdocument" target="_blank" rel="noreferrer noopener">PDFDocument</a> support for creating your own PDFs, and now we’ve added <a href="https://documentation.xojo.com/api/user_interface/mobile/mobilepdfviewer.html#methods" target="_blank" rel="noreferrer noopener">MobilePDFViewer</a> to give you an easy way to show PDF document files from your Android apps.</p>



<h2 class="wp-block-heading"><strong>Zip/Unzip</strong></h2>



<p>The FolderItem class now supports the <a href="https://documentation.xojo.com/api/files/folderitem.html#folderitem-zip" target="_blank" rel="noreferrer noopener">Zip</a> and <a href="https://documentation.xojo.com/api/files/folderitem.html#folderitem-unzip" target="_blank" rel="noreferrer noopener">Unzip</a> methods to make it simple to compress and uncompressed Zip files.</p>



<h2 class="wp-block-heading"><strong>Android Keeps Getting Better</strong></h2>



<p>There are also improvements to <a href="https://documentation.xojo.com/api/user_interface/mobile/mobiletabpanel.html#mobiletabpanel" target="_blank" rel="noreferrer noopener">MobileTabPanel</a>, <a href="https://documentation.xojo.com/api/user_interface/mobile/mobiletextarea.html#mobiletextarea" target="_blank" rel="noreferrer noopener">MobileTextArea</a>, <a href="https://documentation.xojo.com/api/user_interface/mobile/mobileslider.html#mobileslider" target="_blank" rel="noreferrer noopener">MobileSlider</a>, <a href="https://documentation.xojo.com/api/user_interface/mobile/mobilescrollablearea.html#mobilescrollablearea" target="_blank" rel="noreferrer noopener">MobileScrollableArea</a>, <a href="https://documentation.xojo.com/api/hardware/barcode.html#barcode" target="_blank" rel="noreferrer noopener">Barcode</a> and more. With each release, Android gets closer to feature parity with iOS!</p>



<p>And of course, we continue to squash framework and compiler bugs.</p>



<p>Be sure to check out the full <a href="https://documentation.xojo.com/resources/release_notes/2026r1.html" target="_blank" rel="noreferrer noopener">release notes</a> for all the details!</p>



<p><em>Paul learned to program in BASIC at age 13 and has programmed in more languages than he remembers, with Xojo being an obvious favorite. When not working on Xojo, you can find him talking about retrocomputing at <a href="https://goto10.substack.com" target="_blank" rel="noreferrer noopener">Goto 10</a> and </em>on Mastodon @lefebvre@hachyderm.io.</p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Year of Code 2025: November Project – PDF Postcard Generator</title>
		<link>https://blog.xojo.com/2025/11/10/year-of-code-2025-november-project-pdf-postcard-generator/</link>
		
		<dc:creator><![CDATA[Gabriel Ludosanu]]></dc:creator>
		<pubDate>Mon, 10 Nov 2025 22:32:24 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Year of Code]]></category>
		<category><![CDATA[#YearofCode]]></category>
		<category><![CDATA[Graphics]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[PDFDocument]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=15499</guid>

					<description><![CDATA[For November&#8217;s Xojo Year of Code 2025, I’ve created a fun and practical project: a PDF Postcard Generator. This desktop application allows you to easily&#8230;]]></description>
										<content:encoded><![CDATA[
<p>For November&#8217;s Xojo Year of Code 2025, I’ve created a fun and practical project: a PDF Postcard Generator. This desktop application allows you to easily design personalized holiday postcards by combining a chosen image with a custom message, then exporting it as a ready-to-share PDF. It&#8217;s a fantastic way to see Xojo’s capabilities in handling graphics, file operations, and PDF creation, all within a simple, intuitive interface.</p>



<h2 class="wp-block-heading">What this project includes</h2>



<ul class="wp-block-list">
<li>A&nbsp;<code>DesktopWindow</code>&nbsp;(<code>wMain</code>) that provides a clean user interface for selecting an image, inputting your message, and generating the final PDF postcard.</li>



<li>Intelligent image handling that supports common formats like JPG, PNG, and GIF. The application automatically crops your selected image to a perfect 4:6 aspect ratio, ensuring it fits the postcard layout beautifully.</li>



<li>Robust PDF generation, leveraging Xojo&#8217;s&nbsp;<code>PDFDocument</code>&nbsp;and&nbsp;<code>Graphics</code>&nbsp;classes to embed images and render styled text effectively onto the document.</li>



<li>Customizable message rendering, which includes a subtle drop shadow effect for improved readability and a polished look against your background image.</li>



<li>Automated saving of the generated PDF postcard to your desktop, complete with a unique, timestamped filename, and immediate opening of the file in your system&#8217;s default viewer for quick review.</li>
</ul>



<h2 class="wp-block-heading">Download</h2>



<p>You can download the entire Xojo project from <a href="https://github.com/xolabsro/Holiday-Postcard-Generator" target="_blank" rel="noreferrer noopener">GitHub</a>.</p>



<p>This project illustrates Xojo&#8217;s robust capabilities for handling graphics and generating PDFs, demonstrating how straightforward it is to create functional and creative desktop applications. We encourage you to use this postcard generator as a springboard for your own ideas. Perhaps you could expand it by adding features like custom fonts, multiple message fields, or even integration with a data source for personalized bulk postcards. Or, consider how Xojo&#8217;s PDF features could power entirely new applications for reporting, invoicing, or custom document creation. We&#8217;d love to see what you build!</p>



<p><em>Gabriel is a digital marketing enthusiast who loves coding with Xojo to create cool software tools for any platform. He is always eager to learn and share new ideas!</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p><strong>Year of Code Project</strong></p>



<ul class="wp-block-list">
<li><a href="https://blog.xojo.com/2025/01/09/year-of-code-2025-kickoff/">Year of Code: Kickoff</a></li>



<li><a href="https://blog.xojo.com/2025/01/15/year-of-code-2025-january-project/" target="_blank" rel="noreferrer noopener">January Project: Desktop Apps</a>&nbsp;|&nbsp;<a href="https://forum.xojo.com/t/year-of-code-2025-january-project-sharing/83927" target="_blank" rel="noreferrer noopener">Forum Discussion</a></li>



<li><a href="https://blog.xojo.com/2025/02/11/year-of-code-2025-february-project/">February Project: Database Apps</a>&nbsp;|&nbsp;<a href="https://forum.xojo.com/t/2025-year-of-code-february" target="_blank" rel="noreferrer noopener">Forum Discussion</a></li>



<li><a href="https://blog.xojo.com/2025/03/05/year-of-code-2025-march-project-web-apps/">March Project: Web Apps</a> | <a href="https://forum.xojo.com/t/2025-year-of-code-march/84474?u=alyssa_foley">Forum Discussion</a></li>



<li><a href="https://blog.xojo.com/2025/04/08/year-of-code-2025-april-project-user-interface/">April Project: User Interface</a> | <a href="https://forum.xojo.com/t/2025-year-of-code-april-user-interface/84926">Forum Discussion</a></li>



<li><a href="https://blog.xojo.com/2025/05/07/year-of-code-2025-may-project-mobile-apps/">May Project: Mobile Apps</a> | <a href="https://forum.xojo.com/t/2025-year-of-code-may-is-mobile/85272">Forum Discussion</a></li>



<li><a href="https://blog.xojo.com/2025/06/10/year-of-code-2025-june-project-cross-platform-code-class/">June Project: Code Sharing</a> | <a href="https://forum.xojo.com/t/2025-year-of-code-june-is-code-sharing/85612">Forum Discussion</a></li>



<li><a href="https://blog.xojo.com/2025/07/10/year-of-code-2025-july-project-charting/">July Project: Charting</a> | <a href="https://forum.xojo.com/t/2025-year-of-code-july-is-charting/85896">Forum Discussion</a></li>



<li><a href="https://blog.xojo.com/2025/08/07/year-of-code-2025-august-project-console-apps/">August Project: Console Apps</a> | <a href="https://forum.xojo.com/t/august-2025-year-of-code-console-apps/86203">Forum Discussion</a></li>



<li><a href="https://blog.xojo.com/2025/09/08/year-of-code-2025-september-project-games/">September Project: Games</a> | <a href="https://forum.xojo.com/t/2025-year-of-code-septgamer">Forum Discussion</a></li>



<li><a href="https://blog.xojo.com/2025/10/13/year-of-code-2025-october-project-multi-platform-communication/">October Project: Multi-Platform</a> | <a href="https://forum.xojo.com/t/2025-year-of-code-october-multi-platform-communication/86717">Forum Discussion</a></li>



<li><a href="https://blog.xojo.com/2025/11/10/year-of-code-2025-november-project-pdf-postcard-generator/">November Project: PDF</a> | <a href="https://forum.xojo.com/t/2025-year-of-code-november-pdf/86969">Forum Discussion</a></li>
</ul>



<p><strong>How to Play:</strong></p>



<p>Each month we&#8217;ll announce a new theme and share an example project of our own. Share your projects to the Xojo Forum thread for that month via GitHub (all the links you need are posted above ↑ ). Learn how to use <a href="https://blog.xojo.com/2024/04/02/using-xojo-and-github/">Xojo and GitHub</a>.</p>



<p><strong>The Prizes:</strong></p>



<p>Monthly winners get $100 at the Xojo store. Every month you submit a project is another chance to win the grand prize. The grand prize is $250 cash plus a Xojo Pro license and a year of GraffitiSuite and will be announce in December. Learn more about the <a href="https://blog.xojo.com/2025/01/09/year-of-code-2025-kickoff/#prizes">prizes</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Working with PDFTableDataSource from Sources Other Than RowSet</title>
		<link>https://blog.xojo.com/2024/11/25/working-with-pdftabledatasource-from-sources-other-than-rowset/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Mon, 25 Nov 2024 14:00:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Desktop]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[PDF]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=14035</guid>

					<description><![CDATA[Some users on the Xojo Forum recently asked how to render tables on a PDFDocument using the PDFTableDataSource class interface when the dat source does&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Some users on the <a href="https://forum.xojo.com/t/pdftable-created-manually-not-from-rowset-web/83000">Xojo Forum recently</a> asked how to render tables on a PDFDocument using the <a href="https://documentation.xojo.com/api/pdf/pdftabledatasource.html#pdftabledatasource">PDFTableDataSource</a> class interface when the dat source does not comes from a RowSet. Well, the truth is that it doesn&#8217;t differ too much from when it does! Continue reading and I will show you how using a simple example.</p>



<span id="more-14035"></span>



<p>The trick is to handle the data coming from any source with the right data structure, for example, an Array. This example uses a plain text file with several lines and columns separated by the Tab character as the source of the data.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>In order to follow this tutorial, <a href="https://drive.google.com/file/d/14Ve5TllFLGK2TE4MTr4fjutpI4aGV0UE/view?usp=sharing">download the example project</a>.</p>
</blockquote>


<div class="wp-block-image">
<figure class="aligncenter"><img decoding="async" width="1816" height="2378" src="https://blog.xojo.com/wp-content/uploads/2024/11/Screenshot-2024-11-20-at-12.27.22.png" alt="" class="wp-image-14041" srcset="https://blog.xojo.com/wp-content/uploads/2024/11/Screenshot-2024-11-20-at-12.27.22.png 1816w, https://blog.xojo.com/wp-content/uploads/2024/11/Screenshot-2024-11-20-at-12.27.22-229x300.png 229w, https://blog.xojo.com/wp-content/uploads/2024/11/Screenshot-2024-11-20-at-12.27.22-782x1024.png 782w, https://blog.xojo.com/wp-content/uploads/2024/11/Screenshot-2024-11-20-at-12.27.22-768x1006.png 768w, https://blog.xojo.com/wp-content/uploads/2024/11/Screenshot-2024-11-20-at-12.27.22-1173x1536.png 1173w, https://blog.xojo.com/wp-content/uploads/2024/11/Screenshot-2024-11-20-at-12.27.22-1564x2048.png 1564w" sizes="(max-width: 1816px) 100vw, 1816px" /></figure>
</div>


<h2 class="wp-block-heading">Getting the Data</h2>



<p>As you can see in the example project, the text file has been added to the project using a Build > Copy Files Step (the file name is &#8220;Data.txt&#8221;), so it is copied to the Resources folder of the compiled app and available for both debugging and release builds.</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="2224" height="1464" src="https://blog.xojo.com/wp-content/uploads/2024/11/Screenshot-2024-11-20-at-11.18.01.png" alt="" class="wp-image-14037" srcset="https://blog.xojo.com/wp-content/uploads/2024/11/Screenshot-2024-11-20-at-11.18.01.png 2224w, https://blog.xojo.com/wp-content/uploads/2024/11/Screenshot-2024-11-20-at-11.18.01-300x197.png 300w, https://blog.xojo.com/wp-content/uploads/2024/11/Screenshot-2024-11-20-at-11.18.01-1024x674.png 1024w, https://blog.xojo.com/wp-content/uploads/2024/11/Screenshot-2024-11-20-at-11.18.01-768x506.png 768w, https://blog.xojo.com/wp-content/uploads/2024/11/Screenshot-2024-11-20-at-11.18.01-1536x1011.png 1536w, https://blog.xojo.com/wp-content/uploads/2024/11/Screenshot-2024-11-20-at-11.18.01-2048x1348.png 2048w" sizes="auto, (max-width: 2224px) 100vw, 2224px" /></figure>
</div>


<p>Then, in the Pressed event of the Button1 control placed on the default Window1, we will access the contents of the file in order to store each of the lines in the Data Array of strings:</p>



<pre class="wp-block-code"><code>Var f As FolderItem = SpecialFolder.Resource("data.txt")
If f &lt;&gt; Nil And f.Exists Then
  Var tis As TextInputStream = TextInputStream.Open(f)
  Var s As String = tis.ReadAll
  data = s.ToArray(EndOfLine.macOS)
End If</code></pre>



<h2 class="wp-block-heading">PDFRenderer Subclass</h2>



<p>The next step is to create a custom class that will implement the methods provided by the PDFTableDataSource Class Interface. We will name the class &#8220;PDFRenderer&#8221;. Then, from the Inspector Panel, click on the Interfaces button, check the PDFTableDataSource interface and confirm the selection.</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1076" height="1004" src="https://blog.xojo.com/wp-content/uploads/2024/11/Screenshot-2024-11-20-at-11.03.21.png" alt="" class="wp-image-14036" srcset="https://blog.xojo.com/wp-content/uploads/2024/11/Screenshot-2024-11-20-at-11.03.21.png 1076w, https://blog.xojo.com/wp-content/uploads/2024/11/Screenshot-2024-11-20-at-11.03.21-300x280.png 300w, https://blog.xojo.com/wp-content/uploads/2024/11/Screenshot-2024-11-20-at-11.03.21-1024x955.png 1024w, https://blog.xojo.com/wp-content/uploads/2024/11/Screenshot-2024-11-20-at-11.03.21-768x717.png 768w" sizes="auto, (max-width: 1076px) 100vw, 1076px" /></figure>
</div>


<p>Once done, the methods from the class interface will be automatically added to the class:</p>



<ul class="wp-block-list">
<li>AddNewRow</li>



<li>Completed</li>



<li>HeaderHeight</li>



<li>MergeCellsForRow</li>



<li>PaintCell</li>



<li>PaintHeaderContent</li>



<li>RowHeight</li>
</ul>



<p>Over these we will add three more methods:</p>



<h4 class="wp-block-heading">The class Constructor:</h4>



<pre class="wp-block-code"><code>Public Sub Constructor(document As PDFDocument)
  // Simple constructor… just assign the received object
  // to the "Document" property
  
  Self.document = document
  proxy = New Picture(document.Graphics.Width, document.Graphics.Height)
End Sub</code></pre>



<p>Assign the received PDFDocument instance to the document property. It also creates a graphics instance that will be used as a proxy for calculating the height of the processed text from the data (that won&#8217;t be necessary starting with Xojo 2024r4 where some PDFDocument bugs related with that are already fixed).</p>



<h4 class="wp-block-heading">DrawTable:</h4>



<p>This method is the one that will be called to start drawing the table. It will initialize some properties from the received Data (yeah, you can see a property named as &#8220;DrawingFromRowSet&#8221;, but I left that one on purpose because this project is based on the one dealing with the data coming from a RowSet, so you can see how similar all the process is):</p>



<pre class="wp-block-code"><code>Public Sub DrawTable(data() As String, headers() As String)
  // This is the method we call on the Class to draw
  // a table on a PDFDocument based on an Array of Strings
  
  If document &lt;> Nil And data.LastIndex &lt;> -1 Then
    
    // Assign the received Array to the "Data" property
    Self.data = data
    
    // Assign the received headers to the "Headers" property
    Self.Headers = Headers
    
    // Hey! We are going to create a table from an Array
    // so we use a Boolean property as a flag for that
    // (Yeah, we can do it using other techniques, but this
    // is easy enough for this purpose… while leave this
    // helper class "open" enough for drawing tables based on other
    // data sources).
    Self.DrawingFromRowSet = True
    
    // How many columns are we going to draw?
    // Well… as many as columns (TABs) in any of the Array items (for example, the first one).
    Var totalColumns As Integer = data(0).CountFields(Chr(9))
    
    // This is going to be the "drawable area" on the page
    // for the table = total page width less the left and right margins
    Var totalWidth As Double = document.Graphics.Width - 40 // 40 = 20 points left/right margins
    
    // Creating the PDFTable object here!
    Var table As New PDFTable
    
    // We want to repeat the headers on every page
    table.HasRepeatingHeader = True
    
    // Setting the column count for the table
    table.ColumnCount = totalColumns
    
    // …and the width for every column.
    table.ColumnWidths = CalculateColumnWidths(totalWidth, totalColumns)
    
    // The object from this class will be the responsible
    // of handling all the methods associated with the
    // PDFTableDataSouce Class Interface
    table.DataSource = Self
    
    // Setting the Top and Bottom margins for the drawing
    // of the table on every PDF page
    table.TopMargin = 20
    table.BottomMargin = 20
    
    // …and finally we instruct the PDFDocument object
    // to draw the table!
    document.AddTable(table, 20, 0)
    
    // Lastly, clearing the flag
    Self.DrawingFromRowSet = False
    
  End If
End Sub</code></pre>



<h4 class="wp-block-heading">CalculateColumnWidths Method</h4>



<p>This one will calculate the widths for each column to be rendered in the final PDF document.</p>



<pre class="wp-block-code"><code>Protected Function CalculateColumnWidths(TotalWidth As Double, NumberOfColumns As Double) As String
  // Helper method to get a string for the column widths
  
  ColumnWidth = TotalWidth / NumberOfColumns
  Var s() As String
  
  For n As Integer = 0 To NumberOfColumns - 1
    s.Add(Str(ColumnWidth))
  Next
  
  Return String.FromArray(s, ",")
End Function</code></pre>



<h3 class="wp-block-heading">Class Properties</h3>



<p>Because we need to track things like what the current row or column is to be rendered, the headers, etc., our class needs to add some properties:</p>



<ul class="wp-block-list">
<li>Protected Property ColumnWidth As Integer</li>



<li>Public Property CurrentColumn As Integer</li>



<li>Protected Property CurrentHeight As Integer</li>



<li>Protected Property CurrentRow As Integer</li>



<li>Protected Property data() As String</li>



<li>Protected Property document As PDFDocument</li>



<li>Protected Property DrawingFromRowSet As Boolean</li>



<li>Public Property Headers() As String</li>



<li>Protected Property LastRow As Integer</li>



<li>Protected Property proxy As Picture</li>
</ul>



<h3 class="wp-block-heading">PDFTableDataSouce Methods</h3>



<p>Time to visit the methods added by the PDFTableDataSouce class interface. These are the methods called by the <a href="https://documentation.xojo.com/api/pdf/pdftable.html#pdftable">PDFTable</a> object each time it needs to retrieve a piece of information during the rendering on the PDFDocument, as for example if it needs to add a new row, the height for the Header or the current row… and the painting of the row itself!</p>



<h4 class="wp-block-heading">AddNewRow Method</h4>



<p>This one is called by the PDFTable object in order to know if it needs to render a new row in the table:</p>



<pre class="wp-block-code"><code>Protected Function AddNewRow(rowCount As Integer) As Boolean
  // Part of the PDFTableDataSource interface.
  
  If DrawingFromRowSet And data.LastIndex &lt;> -1 then
    
    // We are going to draw as many rows as rows are in the
    // "data" array
    Return rowCount &lt;= data.LastIndex
    
  End If
End Function</code></pre>



<h4 class="wp-block-heading">Completed method</h4>



<p>This is the method invoked by the PDFTable object when it finished drawing the table, so it is your chance to take additional operations, for example, numbering every page of the PDFDocument (we can&#8217;t anticipate that before drawing the table itself):</p>



<pre class="wp-block-code"><code>Protected Sub Completed(x As Double, y As Double)
  // Part of the PDFTableDataSource interface.
  
  // This method is called once the table has been drawed
  // so let's "print" the page number on every page
  // of the PDF Document
  
  Static pageNumber As String = "Page: "
  
  If document &lt;> Nil Then
    Var g As Graphics = document.Graphics
    
    For n As Integer = 1 To document.PageCount
      document.CurrentPage = n
      g.DrawText(pageNumber + Str(n), g.Width - g.TextWidth(pageNumber + Str(n)) - 20, g.Height - g.FontAscent)
    Next
    
  End If
End Sub</code></pre>



<h4 class="wp-block-heading">HeaderHeight Method</h4>



<p>This is the method called by the PDFTable object the returns the height we want to use for rendering the header on the first page and, optionally, on every new page required (added to the document) by rendering the table. In this case we will return a fixed value:</p>



<pre class="wp-block-code"><code>Protected Function HeaderHeight() As Double
  // Part of the PDFTableDataSource interface.
  
  // Returning a fixed height value for the headers
  Return 20
End Function</code></pre>



<h4 class="wp-block-heading">MergeCellsForRow Method</h4>



<p>The PDFTableDataSouce class interface also has the ability to merge cells in the current row, so you can create more elaborated tables. We are not going to use that feature in this example project so it will be empty, no code to be executed.</p>



<h4 class="wp-block-heading">PaintHeaderContent Method</h4>



<p>This is the method in charge of rendering the header for the table, so it receives its own Graphic context with the provided height from the HeaderHeight method and the width calculated from the total of columns (headers) needed to be rendered:</p>



<pre class="wp-block-code"><code>Protected Sub PaintHeaderContent(g As Graphics, column As Integer)
  // Part of the PDFTableDataSource interface.
  
  // Painting the headers for the table
  If column &lt;= Self.Headers.LastIndex Then
    
    Var s As String = headers(column)
    g.DrawingColor = Color.Black
    g.FillRectangle(0, 0, g.Width, g.Height)
    g.DrawingColor = Color.White
    g.DrawText(s, g.Width / 2 - g.TextWidth(headers(column)) / 2, g.Height / 2 + g.FontAscent / 2)
    
  End If
End Sub</code></pre>



<h4 class="wp-block-heading">RowHeight Method</h4>



<p>As the class interface provides a method so we can provide the height for the header, we also have a RowHeight method that the PDFTable object will call before it calls the method in charge of doing the row drawing itself. That way we can have rows of different height based on the height of the own text to be rendered!</p>



<pre class="wp-block-code"><code>Protected Function RowHeight() As Double
  // Part of the PDFTableDataSource interface.
  
  // We need to calculate the height for every row in the Table
  // so let's calculate that based on the taller of the texts (columns)
  // based on text wrapping
  
  If CurrentRow &lt;= data.LastIndex Then
    CurrentHeight = 0
    Var s() As String = data(CurrentRow).Split(Chr(9))
    Var g As Graphics = proxy.Graphics
    Var itemHeight As Integer
    For Each item As String In s
      itemHeight = g.TextHeight(item, ColumnWidth - 40)
      If itemHeight > CurrentHeight Then
        CurrentHeight = itemHeight
      End If
    Next
    
    CurrentRow = CurrentRow  + 1 
    
    Return CurrentHeight + 20
  End If
End Function</code></pre>



<h4 class="wp-block-heading">PaintCell Method</h4>



<p>Lastly, this is the method called by the PDFTable object when it is time to render a given cell for the current row in the table. It receives as parameters both a <a href="https://documentation.xojo.com/api/pdf/pdfgraphics.html#notes">graphic context</a> with the width and height already suited for the data to be rendered, and also the row and column values so you can get the appropriate data for a given cell from the data source:</p>



<pre class="wp-block-code"><code>Protected Sub PaintCell(g As Graphics, row As Integer, column As Integer)
  // Part of the PDFTableDataSource interface.
  
  // Here is where we really do the drawing
  // the received "g" parameter is for a particula table cell
  // based on the row / column parameters
  // so the origin for X/Y coordinates is at 0,0
  
  If DrawingFromRowSet And data.LastIndex >= row Then
    // Drawing the outer rectangle for the cell
    g.DrawRectangle(0, 0, g.Width, g.Height)
    
    // retrieving the text to be drawn from the Array,
    // using the row and column parameters for that.
    Var s As String = data(row).NthField(Chr(9), column + 1)
    
    // Centering vertically the text on the table cell
    // while the X offset is fixed at 5 points.
    g.DrawText(s, 5, g.Height / 2 + g.FontAscent / 2, ColumnWidth - 20)
    
    // Let's keep track of the last row drawed
    LastRow = row
    
  End If
End Sub</code></pre>



<h2 class="wp-block-heading">Time to push the Start button!</h2>



<p>Everything is setup now in our PDFRenderer class, so let&#8217;s get back to the Pressed event of the Button1 control on the default Window1 window. You will remember from the beginning of this tutorial that this is the place where we retrieved the data from the text file. So let&#8217;s add the code to create a PDFDocument instance, a new PDFRenderer instance and do the rendering of the table itself from the data:</p>



<pre class="wp-block-code"><code>If data.LastIndex &lt;&gt; -1 Then
  
  // Creating a new PDFDocument Instance
  Var d As New PDFDocument
  
  // Creating the PDFTable renderer helper object (we pass the PDFDocument object to it in the Constructor)
  Var PDFRender As New PDFRenderer(d)
  
  // These will be the headers drawed in the Table
  Var headers() As String = Array("Name", "Surname", "Address", "City", "Email")
  
  // And let's instruct the PDFTable renderer helper to draw the table
  // based in the SQLite database rowset we got in the previous step
  PDFRender.DrawTable(data, headers)
  
  // …and save the resulting PDF File to the Desktop
  Var out As FolderItem = SpecialFolder.Desktop.Child("TableFromTextFile.pdf")
  
  If out &lt;&gt; Nil Then
    d.Save(out)
    out.Open
  End If
End If</code></pre>



<h2 class="wp-block-heading">Conclusion</h2>



<p>As you see, and if this tutorial is compared with <a href="https://blog.xojo.com/2023/01/17/pdftable-from-a-rowset/">PDFTable from a RowSet</a>, creating a PDFTable doesn&#8217;t differ too much when using a data source other than a RowSet. All you need, basically, is to keep track of the current row, know if you need to render more rows and a base data structure that can be used to retrieve the data to be rendered in a given Row/Column.</p>



<p>As always, you can learn more about other features provided by <a href="https://documentation.xojo.com/api/pdf/pdfdocument.html#pdfdocument">PDFDocument in the Xojo Documentation</a>.</p>



<p>Happy Coding!</p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Tutorial: Design a Control to Dynamically Preview Images and PDF Files</title>
		<link>https://blog.xojo.com/2024/03/11/tutorial-design-a-control-to-dynamically-preview-images-and-pdf-files/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Mon, 11 Mar 2024 15:00:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Desktop]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Composition]]></category>
		<category><![CDATA[ContainerControl]]></category>
		<category><![CDATA[Control]]></category>
		<category><![CDATA[Multi-Platform Development]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=12601</guid>

					<description><![CDATA[In this tutorial learn to design a cross-platform control that dynamically previews images and PDF files. Files can dragged and dropped onto the control, opened from the standard file selection dialog, and, in the case of images, added using Copy and Paste. The file path will be displayed below the addendum file. ]]></description>
										<content:encoded><![CDATA[
<p>A few days ago, I received a request from a user about how to solve a problem he was facing in a control for one of the desktop applications used by his company. This is the scenario:</p>



<ul class="wp-block-list">
<li>The control should show previews of images and PDF documents.</li>



<li>The documents to be displayed can be dragged and dropped onto the control, or opened from the standard file selection dialog.</li>



<li>In the case of images, they can also be added to the control using Copy and Paste.</li>



<li>In any of the above cases, the path of the file in question must be received so that future actions can be carried out.</li>
</ul>



<p>As an additional point, since we are using Xojo, the control will be cross-platform and functional on macOS, Windows and Linux.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><a href="https://drive.google.com/file/d/1TCFB8fNq2bZu7i1KMhWYCV26LdXK6Ykz/view?usp=share_link">Download the Example Project</a>.</p>
</blockquote>



<h2 class="wp-block-heading">Preparation</h2>



<p>Taking into account these requirements, as well as considering that the same problem may have more than one solution, this tutorial will show you how to create a control using the <a href="https://en.wikipedia.org/wiki/Composition_over_inheritance">Composition technique</a>. Using this technique, several graphical interface controls will be used internally and their use will be transparent to users who use it globally, either when creating their own applications or when using the control on any desktop platform.</p>



<p>When it comes to creating a control using the Composition technique, the DesktopContainerControl is the best candidate. A new ContainerControl-based class would internally use the following core controls:</p>



<ol class="wp-block-list">
<li>The DesktopImageWell control which is ideal for displaying images. </li>



<li>The DesktopHTMLViewer control which is ideal for displaying the preview of PDF documents.</li>
</ol>



<p>Now, while DesktopImageWell supports displaying images directly using Drag and Drop, this is not the case with the DesktopHTMLViewer control; so if the user of the control tried to drag and drop a PDF document or image when the HTMLViewer is displaying the control, it wouldn&#8217;t work.</p>



<p>To solve this situation it is common to add a third control. We&#8217;ll use a DesktopCanvas that will be, at all times, the top layer regardless of which underlying control (either the ImageWell or the HTMLViewer) is displayed. Thus, the DesktopCanvas would capture the event corresponding to the user dragging a file onto the global control (the class based on ContainerControl). Since it is transparent, it will not prevent the preview of the image or PDF file to be seen in the bottom layer control, at least on macOS.</p>



<p>But the Canvas is not transparent on Windows, in this case we need to use conditional compilation at various points in the class to modify the user interface of the main ContainerControl so that it adds a special area located under the controls preview (ImageViewer or HTMLViewer), and which will be used by the user of the control to drag and drop the corresponding files. For this we will use an additional DesktopCanvas.</p>



<p>Of course, we will also have to add a button to our control that will be responsible for opening the standard file selection dialog box so that the user can choose the file to preview.</p>



<p>To deal with another small difference between macOS and Windows, we will add a DesktopRectangle to be used as the base layer of the control (Z axis), so that it displays the typical Focus ring when the control is active and selected.</p>



<h2 class="wp-block-heading">Designing the Control</h2>



<p>With all that in mind, start a new Desktop project in Xojo. Drag a DesktopContainer from the Library onto the Navigator. It will look like this:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="774" src="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-1-1024x774.png" alt="" class="wp-image-12602" srcset="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-1-1024x774.png 1024w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-1-300x227.png 300w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-1-768x581.png 768w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-1-1536x1161.png 1536w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-1-2048x1548.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>With the new Desktop Container1 instance selected in the Navigator, use the Inspector Panel to change the following values:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> ImagePDFContainer </li>



<li><strong>Size &gt; Width</strong>: 220 </li>



<li><strong>Size &gt; Height:</strong> 200</li>
</ul>



<p>Next, add the Drag and Drop area which, remember, will be shown only when the control is executed on Windows. To do this, drag a DesktopCanvas from the Library and drop it in the area of the Layout Editor corresponding to the Design Editor, placing it right under the container for our own convenience.</p>



<p>With Canvas1 selected, use the Inspector Panel to change the following values:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> DropArea</li>



<li><strong>Position &gt; Left:</strong> 1</li>



<li><strong>Position &gt; Top:</strong> 221</li>



<li><strong>Position &gt; Width:</strong> 216</li>



<li><strong>Position &gt; Height:</strong> 100</li>
</ul>



<p>The design should look like this:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="774" src="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-2-1024x774.png" alt="" class="wp-image-12603" srcset="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-2-1024x774.png 1024w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-2-300x227.png 300w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-2-768x581.png 768w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-2-1536x1161.png 1536w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-2-2048x1548.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Now, add the background layer. This is the layer that will be in charge of displaying the focus ring for the control in Windows. To do this, drag a DesktopRectangle from the Library and drop it on the ContainerControl in the Layout Editor. The ContainerControl should show a red box indicating that the dragged control will be contained as a child control in the Container itself. Next, with DesktopRectangle1 still selected in the Layout Editor, use the Inspector Panel to modify the following values:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> BacktroundRect</li>



<li><strong>Position &gt; Left:</strong> 0</li>



<li><strong>Position &gt; Top:</strong> 0</li>



<li><strong>Position &gt; Width:</strong> 220</li>



<li><strong>Position &gt; Height:</strong> 200</li>



<li><strong>Locking:</strong> Lock all four padlocks.</li>
</ul>



<p>Next, add the button responsible for displaying the standard dialog box for selecting the file to preview. Drag a DesktopPushButton from the Library and drop it onto the bottom of the Container in the Layout Editor. The Container should display a red box to indicate that the button will be added as a child control in the Container itself.</p>



<p>Then, with Button1 still selected in the Layout Editor, use the associated Inspector Panel to change the following values:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> OpenFileButton</li>



<li><strong>Position &gt; Left:</strong> 0</li>



<li><strong>Position &gt; Top:</strong> 0</li>



<li><strong>Position &gt; Width:</strong> 178</li>



<li><strong>Position &gt; Height:</strong> 22</li>



<li><strong>Locking:</strong> Closes the left, right and bottom locks. Open the lock on the top edge.</li>



<li><strong>Mac Button Style:</strong> Recessed</li>



<li><strong>Caption:</strong> Open File…</li>
</ul>



<p>At this point, the control layout should look something like this:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="774" src="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-3-1024x774.png" alt="" class="wp-image-12604" srcset="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-3-1024x774.png 1024w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-3-300x227.png 300w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-3-768x581.png 768w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-3-1536x1161.png 1536w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-3-2048x1548.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Now, add the instance of the DesktopImageViewer control responsible for previewing the images. As in previous steps, drag the DesktopImageViewer control from the Library and drop it on the Layout Editor, in the upper right part of the Container; then, with ImageViewer1 still selected, use the associated Inspector Panel to change the following values:</p>



<ul class="wp-block-list">
<li><strong>Name: </strong>ImagePreviewer</li>



<li><strong>Position &gt; Left: </strong>238</li>



<li><strong>Position &gt; Top:</strong> -219</li>



<li><strong>Position &gt; Width:</strong> 218</li>



<li><strong>Position &gt; Height:</strong> 198</li>



<li><strong>Locking:</strong> Lock all four padlocks.</li>
</ul>



<p>Drag a DesktopHTMLViewer from the Library onto the free area of the Layout Editor, just below the ImageViewer added in the previous step; Then, with HTMLViewer1 still selected in the Layout Editor, use the associated Inspector Panel to modify the following values:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> HTMLPDF</li>



<li><strong>Position &gt; Left:</strong> 238</li>



<li><strong>Position &gt; Top:</strong> 0</li>



<li><strong>Position &gt; Width:</strong> 218</li>



<li><strong>Position &gt; Height:</strong> 198</li>



<li><strong>Locking: </strong>Lock all four padlocks.</li>
</ul>



<p>At this point, the control layout should look something like this:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="774" src="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-4-1024x774.png" alt="" class="wp-image-12605" srcset="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-4-1024x774.png 1024w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-4-300x227.png 300w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-4-768x581.png 768w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-4-1536x1161.png 1536w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-4-2048x1548.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Finally, add the overlay to be used only when the control is executed on macOS and that is responsible for capturing the action of &#8220;Drag and Drop&#8221; files by the user. Drag a new DesktopCanvas over the Container in the Layout Editor. The Container should display a red box to indicate that the new control is being added as a child of the Container itself. With Canvas1 still selected in the Layout Editor, use the associated Inspector Panel to modify the following values:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> CanvasOverlay</li>



<li><strong>Position &gt; Left:</strong> 1</li>



<li><strong>Position &gt; Top:</strong> 1</li>



<li><strong>Position &gt; Width:</strong> 218</li>



<li><strong>Position &gt; Height:</strong> 179</li>



<li><strong>Locking:</strong> Lock all four padlocks.</li>
</ul>



<p>To make sure that all the &#8220;layers&#8221; (order of the controls on the Z axis) are as we expect, click on the &#8220;Show Tab Order&#8221; button in the Layout Editor toolbar. If they do not match the order shown in the image below, drag and drop each element to the correct position in the list:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="774" src="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-5-1024x774.png" alt="" class="wp-image-12606" srcset="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-5-1024x774.png 1024w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-5-300x227.png 300w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-5-768x581.png 768w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-5-1536x1161.png 1536w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-5-2048x1548.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading">Add Functionality</h2>



<p>With the design of the control now complete, it is time to add its functionality. To do this, select ImagePDFContainer in the Navigator and add the following properties along with the values indicated in the Inspector Panel:</p>



<p>The first will be in charge of containing the message to be displayed in the &#8220;Drag and Drop&#8221; area:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> DropFileMessage</li>



<li><strong>Type:</strong> String </li>



<li><strong>Scope:</strong> Public</li>
</ul>



<p>The second will be the property in charge of storing the reference to the file (FolderItem instance) whose image/PDF is being previewed:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> FileDropped</li>



<li><strong>Type:</strong> FolderItem </li>



<li><strong>Scope:</strong> Private</li>
</ul>



<p>The last property will be responsible for containing the color to be used as the focus ring:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> FocusColor</li>



<li><strong>Type:</strong> Color </li>



<li><strong>Scope:</strong> Public</li>
</ul>



<p>Next, add the events that the control needs to consume for its operation. With ImagePDFContainer still selected in the Navigator, add the following Event Handlers along with the associated code:</p>



<h4 class="wp-block-heading">Opening:</h4>



<pre id="Xojo" class="wp-block-code"><code>HTMLPDF.Visible = False
ImagePreviewer.Visible = False

#If TargetWindows Then
  DropArea.Top = Me.Height - 50
  DropArea.Height = 50
  DropArea.Width = BackgroundRect.Width
  DropArea.Left = BackgroundRect.Left
  BackgroundRect.Height = BackgroundRect.Height - 50
  
  HTMLPDF.Height = BackgroundRect.Height - 2
  ImagePreviewer.Height = BackgroundRect.Height - 2
#EndIf

RaiseEvent Opening</code></pre>



<h4 class="wp-block-heading">MouseDown:</h4>



<pre id="Xojo" class="wp-block-code"><code>Me.SetFocus
Return True</code></pre>



<h4 class="wp-block-heading">FocusReceived:</h4>



<pre class="wp-block-code"><code>#If TargetWindows Then
  FocusColor = Color.Blue
  BackgroundRect.BorderColor = FocusColor
  DropArea.Refresh
#EndIf</code></pre>



<h4 class="wp-block-heading">FocusLost:</h4>



<pre class="wp-block-code"><code>#If TargetWindows Then
  FocusColor = Color.Black
  BackgroundRect.BorderColor = FocusColor
  DropArea.Refresh
#EndIf</code></pre>



<p>Since the Opening event is used by our ImagePDFContainer subclass, add an event definition with the same name so that instances created from it can also add their own Opening event handler and include any additional code to execute as desired.</p>



<p>Then, add an additional event definition (FileDropped) that will be the one sent by the ImagePDFContainer subclass to the instances created from it, and that implement it, to pass them as a parameter the FolderItem corresponding to the file opened / dragged and dropped / or , in the case of images, that have been pasted on the control.</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> FileDropped</li>



<li><strong>Parameters:</strong> file As FolderItem</li>
</ul>



<p>Since we want to support pasting images onto the control, we also need to add a MenuHandler to the ImagePDFContainer subclass. To do this, with ImagePDFContainer still selected in the Navigator, select the option Add to &#8220;ImagePDFContainer&#8221; &gt; Menu Handler&#8230;</p>



<p>Use the following values in the associated Inspector Panel:</p>



<ul class="wp-block-list">
<li><strong>MenuItem Name:</strong> EditPaste</li>
</ul>



<p>And add the following code in the Code Editor associated with the Menu Handler:</p>



<pre id="Xojo" class="wp-block-code"><code>Var pb As New Clipboard
If pb.PictureAvailable Then
  Var f As FolderItem = SpecialFolder.Temporary.Child("temp-pict.png")
  If f.Exists Then f.Remove
  If f &lt;&gt; Nil Then
    pb.Picture.Save(f, Picture.Formats.PNG)
    FileDropped = f
    PreviewFile(FileDropped)
  End If
  Return True
End If

Return False</code></pre>



<p>To complete this section, add a new method to ImagePDFContainer and use the following values in the associated Inspector Panel:</p>



<ul class="wp-block-list">
<li><strong>Method Name:</strong> PreviewFile</li>



<li><strong>Parameters:</strong> f As FolderItem</li>
</ul>



<p>Add the following code in the associated Code Editor:</p>



<pre id="Xojo" class="wp-block-code"><code>FileDropped = f

If f &lt;> Nil Then
  
  If FileDropped.Name.EndsWith(".pdf") Then
    ImagePreviewer.Visible = False
    HTMLPDF.Visible = True
    
    HTMLPDF.Top = BackgroundRect.Top + 1
    HTMLPDF.Left = BackgroundRect.Left + 1
    
    #If TargetWindows Then
      HTMLPDF.Height = BackgroundRect.Height - OpenFileButton.Height
    #Else
      HTMLPDF.Height = Self.Height - OpenFileButton.Height
    #EndIf
    
    HTMLPDF.LoadPage(FileDropped)
    
  Else
    
    Var p As Picture = Picture.Open(FileDropped)
    
    If p &lt;> Nil Then
      ImagePreviewer.Top = BackgroundRect.Top + 1
      ImagePreviewer.Left = BackgroundRect.Left + 1
      
      #If TargetWindows Then
        ImagePreviewer.Height = BackgroundRect.Height - OpenFileButton.Height
      #Else
        ImagePreviewer.Height = Self.Height - OpenFileButton.Height
      #EndIf
      
      ImagePreviewer.Image = p
      HTMLPDF.Visible = False
      ImagePreviewer.Visible = True
      
    End If
    
  End If
  
  RaiseEvent FileDropped(FileDropped)
  
Else
  HTMLPDF.Visible = False
  ImagePreviewer.Visible = False
End If</code></pre>



<h2 class="wp-block-heading">Add Functionality to Controls</h2>



<p>Now it&#8217;s time to add functionality to the controls. Select the CanvasOverlay item in the Navigator and add the following Event Handlers along with the code given below:</p>



<h4 class="wp-block-heading">Opening:</h4>



<pre class="wp-block-code"><code>Me.AcceptFileDrop("application/pdf")
Me.AcceptFileDrop("image/png")
Me.AcceptFileDrop("image/jpg")

#If TargetWindows Then
  Me.Visible = False
#EndIf</code></pre>



<h4 class="wp-block-heading">DropObject:</h4>



<pre class="wp-block-code"><code>#Pragma Unused action

If obj.FolderItemAvailable Then
  PreviewFile(obj.FolderItem)
End If</code></pre>



<h4 class="wp-block-heading">MouseDown:</h4>



<pre class="wp-block-code"><code>#Pragma Unused x
#Pragma Unused y

Self.SetFocus</code></pre>



<p>Now select the DropArea item in the Navigator and add the following Event Handlers along with the code indicated below:</p>



<h4 class="wp-block-heading">Opening:</h4>



<pre class="wp-block-code"><code>Me.AcceptFileDrop("application/pdf")
Me.AcceptFileDrop("image/png")
Me.AcceptFileDrop("image/jpg")

#If TargetMacOS Then
  Me.Visible = False
#EndIf</code></pre>



<h4 class="wp-block-heading">DropObject:</h4>



<pre class="wp-block-code"><code>#Pragma Unused action

If obj.FolderItemAvailable Then
  PreviewFile(obj.FolderItem)
End If</code></pre>



<h4 class="wp-block-heading">Paint:</h4>



<pre class="wp-block-code"><code>#Pragma Unused areas

g.DrawingColor = FocusColor
g.PenSize = 2.0
g.DrawRectangle(0, 0, g.Width, g.Height)
g.PenSize = 1.0

If DropFileMessage &lt;> "" Then
  
  g.DrawingColor = Color.Black
  
  Var textLength As Double = g.TextWidth(DropFileMessage)
  Var x, y As Double
  
  x = Me.Width / 2 - textLength / 2
  y = Me.Height / 2 + g.TextHeight / 2
  
  g.DrawText(DropFileMessage, x, y)
  
End If</code></pre>



<p>Now select the HTMLPDF item in the Navigator and add the Event Handlers along with the code indicated below:</p>



<h4 class="wp-block-heading">MouseDown:</h4>



<pre class="wp-block-code"><code>#Pragma Unused x
#Pragma Unused y

Self.SetFocus</code></pre>



<p>Next, select the ImagePreviewer item in the Navigator and add the following Event Handlers along with the code below:</p>



<h4 class="wp-block-heading">MouseDown:</h4>



<pre class="wp-block-code"><code>#Pragma Unused x
#Pragma Unused y

Self.SetFocus</code></pre>



<p>Finally, select the OpenFileButton item in the Navigator and add the following Event Handlers along with the code indicated below:</p>



<h4 class="wp-block-heading">Pressed:</h4>



<pre class="wp-block-code"><code>Var f As FolderItem = FolderItem.ShowOpenFileDialog("")

If f &lt;> Nil Then
  Self.PreviewFile(f)
End If</code></pre>



<h2 class="wp-block-heading">Testing the ImagePDFContainer Control</h2>



<p>We have completed the design and added the required functionality to our control, now it is time to add an instance to the project window so we can test its operation.</p>



<p>Select Window1 in the Navigator so that the associated Layout Editor is displayed. Next drag ImagePDFContainer from the Navigator and drop it onto the Layout Editor, using the following values in the associated Inspector Panel:</p>



<ul class="wp-block-list">
<li><strong>Size &gt; Width: </strong>220</li>



<li><strong>Size &gt; Height:</strong> 200</li>



<li><strong>Locking:</strong> Lock all four padlocks</li>



<li><strong>Appearance &gt; Allow Focus Ring:</strong> Enabled </li>



<li><strong>Behavior &gt; Allow Focus: </strong>Enabled.</li>



<li><strong>Behavior &gt; Allow Tabs:</strong> Enabled.</li>
</ul>



<p>With ImagePDFContainer1 selected in the Navigator, add the following Event Handlers along with the code below:</p>



<h4 class="wp-block-heading">Opening:</h4>



<pre class="wp-block-code"><code>Me.DropFileMessage = "Drop Files Here"</code></pre>



<h4 class="wp-block-heading">FileDropped:</h4>



<pre class="wp-block-code"><code>LastFolderItemNameLabel.Text = file.NativePath</code></pre>



<p>As you can see, this is referring to the LastFolderItemNameLabel control that we have not yet added to the window layout yet; So, let&#8217;s do that.</p>



<p>Select Window1 in the Navigator to access the associated Layout Editor. Drag a Label control from the Library and drop it onto the bottom of the window in the Layout Editor, then use the following values in the associated Inspector Panel:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> Label1</li>



<li><strong>Position &gt; Left:</strong> 28</li>



<li><strong>Position &gt; Top: </strong>360</li>



<li><strong>Position &gt; Width:</strong> 150</li>



<li><strong>Position &gt; Height:</strong> 20</li>



<li><strong>Locking:</strong> Lock the left and bottom padlock. Unlock the top and right locks.</li>



<li><strong>Text:</strong> Last FolderItem Path:</li>
</ul>



<p>Add a second Label from the Library to the right of the previous one, using the following values in the associated Inspector Panel:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> LastFolderItemNameLabel</li>



<li><strong>Position &gt; Left: </strong>190</li>



<li><strong>Position &gt; Top:</strong> 360</li>



<li><strong>Position &gt; Width:</strong> 390</li>



<li><strong>Position &gt; Height:</strong> 20</li>



<li><strong>Locking: </strong>Locks the left, bottom and right padlocks. Unlock the top lock.</li>



<li><strong>Text:</strong> (empty)</li>
</ul>



<h2 class="wp-block-heading">Run the Application</h2>



<p>Ready! Run the application and try dragging and dropping image files (JPEG or PNG), as well as PDF files on the control. You should see the change on the fly, showing the most appropriate viewer for each type of file. It will also display the path of the file at the bottom of the window.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="886" src="https://blog.xojo.com/wp-content/uploads/2024/02/Final-1024x886.png" alt="" class="wp-image-12607" srcset="https://blog.xojo.com/wp-content/uploads/2024/02/Final-1024x886.png 1024w, https://blog.xojo.com/wp-content/uploads/2024/02/Final-300x260.png 300w, https://blog.xojo.com/wp-content/uploads/2024/02/Final-768x665.png 768w, https://blog.xojo.com/wp-content/uploads/2024/02/Final-1536x1329.png 1536w, https://blog.xojo.com/wp-content/uploads/2024/02/Final.png 1648w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>You can also click on the button to select the file to display or try copying images and pasting them directly on the control. If you do this, a temporary file will be created so that one of the initial requirements is satisfied: being able to continue working with the file corresponding to the image or PDF document.</p>



<p>As I mentioned at the beginning, this is just one of the possible implementations. I hope you have learned a few things along the way in, for example:</p>



<ul class="wp-block-list">
<li>Redefine Events consumed by a base class.</li>



<li>Create your own Class Events and how to launch them to &#8220;pass&#8221; information to the instances created from said class.</li>



<li>Capture and work with Menu Handlers.</li>



<li>Use of Conditional Compilation so that certain sections of code run only on one platform or another.</li>



<li>And, of course, how to make several UI controls cooperate and present themselves as a single control to the developer and end user who are going to use them.</li>
</ul>



<p>I hope you found it interesting. You are welcome to modify and expand the project to better suit your purposes!</p>



<p>Have fun and keep coding with Xojo!</p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>PDFViewer for Xojo iOS Projects</title>
		<link>https://blog.xojo.com/2023/08/09/pdfviewer-arrives-to-ios-projects/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Wed, 09 Aug 2023 13:30:00 +0000</pubDate>
				<category><![CDATA[iOS]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=11685</guid>

					<description><![CDATA[Many users asked for a way to view and navigate the pages of a PDF document in their iOS projects. Now, starting with Xojo 2023r2 that is possible through the new MobilePDFViewer control. Continue reading to get some hints about how to use it in your iOS projects.]]></description>
										<content:encoded><![CDATA[
<p>Many users asked for a way to view and navigate the pages of a PDF document in their iOS projects. Starting with <a href="http://www.xojo.com/download">Xojo 2023r2</a>, this is possible with the new <a href="https://documentation.xojo.com/api/user_interface/mobile/mobilepdfviewer.html">MobilePDFViewer</a> control. Continue reading to get tips on how to use this in your iOS projects.</p>



<span id="more-11685"></span>



<p>The use of this control is pretty straightforward. Add it to the layout of a Screen in your iOS project. You can use the Inspector Panel to set the background color (by default it is white) and whether it displays the page thumbnails. Of course, the available properties can also be set via code.</p>



<p>Here&#8217;s how it looks running in the Simulator:</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="473" height="1024" src="https://blog.xojo.com/wp-content/uploads/2023/07/Simulator-Screenshot-iPhone-14-2023-07-13-at-09.30.39-473x1024.png" alt="" class="wp-image-11687" srcset="https://blog.xojo.com/wp-content/uploads/2023/07/Simulator-Screenshot-iPhone-14-2023-07-13-at-09.30.39-473x1024.png 473w, https://blog.xojo.com/wp-content/uploads/2023/07/Simulator-Screenshot-iPhone-14-2023-07-13-at-09.30.39-139x300.png 139w, https://blog.xojo.com/wp-content/uploads/2023/07/Simulator-Screenshot-iPhone-14-2023-07-13-at-09.30.39-768x1662.png 768w, https://blog.xojo.com/wp-content/uploads/2023/07/Simulator-Screenshot-iPhone-14-2023-07-13-at-09.30.39-710x1536.png 710w, https://blog.xojo.com/wp-content/uploads/2023/07/Simulator-Screenshot-iPhone-14-2023-07-13-at-09.30.39-946x2048.png 946w, https://blog.xojo.com/wp-content/uploads/2023/07/Simulator-Screenshot-iPhone-14-2023-07-13-at-09.30.39.png 1170w" sizes="auto, (max-width: 473px) 100vw, 473px" /></figure>
</div>


<p>You will then need to tell the PDFViewer which PDF file to display. Do this by assigning the FolderItem to the document property of the PDFViewer control instance. The following lines of code assigns document that has been added to the Resources folder using a Copy File step in the IDE:</p>



<pre id="Xojo" class="wp-block-preformatted"><code>Var f As FolderItem = SpecialFolder.Resource("SampleDocument.pdf")

If f &lt;&gt; Nil And f.Exists Then
  PDFViewer1.Document = f
End If</code></pre>



<p>It is also possible to change the layout of the pages in the PDFViewer with the DisplayMode property that accepts any of the values of the MobilePDFViewer.DisplayModes Enumeration:</p>



<ul class="wp-block-list">
<li>SinglePage</li>



<li>SinglePageContinuous</li>



<li>TwoUp</li>



<li>TwoUpContinuous</li>
</ul>



<p>It is possible to get the number of pages in the document through the Pages property. You can jump to a specific page in the PDF by setting its number using the Page property.</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="139" height="300" src="https://blog.xojo.com/wp-content/uploads/2023/07/Simulator-Screenshot-iPhone-14-2023-07-13-at-09.30.49-139x300.png" alt="" class="wp-image-11686" srcset="https://blog.xojo.com/wp-content/uploads/2023/07/Simulator-Screenshot-iPhone-14-2023-07-13-at-09.30.49-139x300.png 139w, https://blog.xojo.com/wp-content/uploads/2023/07/Simulator-Screenshot-iPhone-14-2023-07-13-at-09.30.49-473x1024.png 473w, https://blog.xojo.com/wp-content/uploads/2023/07/Simulator-Screenshot-iPhone-14-2023-07-13-at-09.30.49-768x1662.png 768w, https://blog.xojo.com/wp-content/uploads/2023/07/Simulator-Screenshot-iPhone-14-2023-07-13-at-09.30.49-710x1536.png 710w, https://blog.xojo.com/wp-content/uploads/2023/07/Simulator-Screenshot-iPhone-14-2023-07-13-at-09.30.49-946x2048.png 946w, https://blog.xojo.com/wp-content/uploads/2023/07/Simulator-Screenshot-iPhone-14-2023-07-13-at-09.30.49.png 1170w" sizes="auto, (max-width: 139px) 100vw, 139px" /></figure>
</div>


<p>Lastly, another useful feature of the PDFViewer control is being able to call the Content method in order to retrieve all the text found in the document. To learn more about all the great new PDF features in Xojo, check out the <a href="https://blog.xojo.com/tag/pdf/">PDF tag</a> of the Xojo Programming Blog.</p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Graphic Charts for Xojo Desktop and Mobile</title>
		<link>https://blog.xojo.com/2023/03/28/graphic-charts-for-xojo-desktop-and-mobile/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Tue, 28 Mar 2023 11:00:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Desktop]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Charts]]></category>
		<category><![CDATA[Data Visualization]]></category>
		<category><![CDATA[Graphics]]></category>
		<category><![CDATA[Graphing]]></category>
		<category><![CDATA[Multi-Platform Development]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[Xojo Code]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=11320</guid>

					<description><![CDATA[Graphic Charts support is new in Xojo Desktop and Xojo Mobile (iOS) in Xojo 2023r1. Graphic Charts offer a similar look and behavior to what you find when using Xojo's WebChart control in web projects. Let's review all the things you can do with the new DesktopChart in your desktop projects, and new MobileChart in your iOS projects.]]></description>
										<content:encoded><![CDATA[
<p>Graphic chart support is new in Xojo Desktop and Xojo Mobile (iOS) in Xojo 2023r1. The new DesktopChart and MobileChart offer a similar look and behavior to what you find when using Xojo&#8217;s WebChart. Let&#8217;s review all the things you can do with the new DesktopChart and MobileChart in your Xojo projects.</p>



<span id="more-11320"></span>



<p>Just as with Xojo&#8217;s <a href="https://documentation.xojo.com/api/user_interface/web/webchart.html#webchart">WebChart</a>, <a href="https://documentation.xojo.com/api/user_interface/desktop/desktopchart.html">DesktopChart</a> and <a href="https://documentation.xojo.com/api/user_interface/mobile/mobilechart.html">MobileChart</a> offer the following chart types: Line, Bar, Pie, Doughnut, PolarArea, Scatter, Bubble and Radar. You can access these charts using the Inspector Panel or via code through the Mode property. You can even change the Mode (or chart type) at runtime on Desktop and Mobile.</p>


<div class="wp-block-image size-large wp-image-11322 is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="641" src="https://blog.xojo.com/wp-content/uploads/2023/02/ChartModeDesktop-1024x641.png" alt="" class="wp-image-11322" srcset="https://blog.xojo.com/wp-content/uploads/2023/02/ChartModeDesktop-1024x641.png 1024w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartModeDesktop-300x188.png 300w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartModeDesktop-768x481.png 768w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartModeDesktop-1536x962.png 1536w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartModeDesktop.png 2032w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">DesktopChart Mode set in the Inspector Panel.</figcaption></figure>
</div>

<div class="wp-block-image size-large wp-image-11323 is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="832" src="https://blog.xojo.com/wp-content/uploads/2023/02/ChartModeiOS-1024x832.png" alt="" class="wp-image-11323" srcset="https://blog.xojo.com/wp-content/uploads/2023/02/ChartModeiOS-1024x832.png 1024w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartModeiOS-300x244.png 300w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartModeiOS-768x624.png 768w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartModeiOS-1536x1248.png 1536w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartModeiOS.png 1758w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">MobileChart Mode set in the Inspector Panel.</figcaption></figure>
</div>


<p>Line and Bar types are similar; both display sets of data that have been set to Line or Bar Modes. Display as many data sets as you need in your DesktopChart or MobileChart by setting the Mode to Line or Bar.&nbsp;The only difference is how these will be displayed along the x axis.</p>



<p>To better understand, let&#8217;s write some code in the Opening Event Handler of a DesktopChart control added to a Desktop project:</p>



<pre class="wp-block-code xojo"><code><code>Var labels() As String
Var firstSetOfData() As Double
Var secondSetOfData() As Double
Var thirdSetOfData() As Double

For n As Integer = 0 To 9
  labels.add "LB"+n.ToString
  firstSetOfData.add System.Random.InRange(0,1000)
  secondSetOfData.add System.Random.InRange(0,1000)
  thirdSetOfData.add System.Random.InRange(0,1000)
Next

Me.mode = DesktopChart.Modes.Line
Me.Title = "Chart Example With Two Datasets"
Me.AddLabels labels

Var DS1 As New ChartLinearDataset("DS1", Color.Blue, True, firstSetOfData)
DS1.ChartType = ChartLinearDataset.ChartTypes.Line

Var DS2 As New ChartLinearDataset("DS2", Color.Red, True, secondSetOfData)
DS2.ChartType = ChartLinearDataset.ChartTypes.Bar

Var DS3 As New ChartLinearDataset("DS2", Color.Green, True, thirdSetOfData)
DS3.ChartType = ChartLinearDataset.ChartTypes.Bar

Me.AddDatasets DS1, DS2, DS3</code></code></pre>



<p>This is how it will look when the Chart has been set to Line, displaying three data sets: one of which has been set to Line and the other two to Bar:</p>


<div class="wp-block-image size-large wp-image-11321 is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="777" src="https://blog.xojo.com/wp-content/uploads/2023/02/ChartSetToLine-1024x777.png" alt="" class="wp-image-11321" srcset="https://blog.xojo.com/wp-content/uploads/2023/02/ChartSetToLine-1024x777.png 1024w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartSetToLine-300x228.png 300w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartSetToLine-768x582.png 768w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartSetToLine.png 1424w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Chart instance set to Line Mode.</figcaption></figure>
</div>


<p>As you can see, when the ChartType is Line, the data sets that are set to Line start drawing at the origin of the X axis, where the labels are also drawn for each column of data. This also happens when drawing data sets whose ChartType is set to Bar; thus, the first bar on the first column has half the width.</p>



<p>Below shows the same data sets but the ChartType is Bar. Now the Bar data sets overlay the position for the labels drawn along the X axis (they are centered on each column), and also have full the width. However, because of that, the data set whose ChartType is set to Line starts drawing at half the width of the column.</p>


<div class="wp-block-image wp-image-11324 size-large is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="777" src="https://blog.xojo.com/wp-content/uploads/2023/02/ChartSetToBar-1024x777.png" alt="" class="wp-image-11324" srcset="https://blog.xojo.com/wp-content/uploads/2023/02/ChartSetToBar-1024x777.png 1024w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartSetToBar-300x228.png 300w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartSetToBar-768x582.png 768w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartSetToBar.png 1424w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Chart instance set to Bar Mode.</figcaption></figure>
</div>


<p>You can add as many new data sets as you want, remove them, update their values, color, etc. The chart will update to reflect the changes, including the minimum and maximum values displayed in the Y axis. Keep in mind, if a chart&#8217;s Mode has been set to Line or Bar it will only display data sets created as ChartLinearDataset (by default they are set to the Line ChartType). WebChart will behave the same, starting with Xojo 2023r1.</p>



<p>One difference to note when using ChartLinearDataset is that you can set the Transparency property ranging from 0 (fully opaque) to 100 (fully transparent), as well as the CornerSize when the ChartLinearDataset ChartType is set to Bar.</p>



<h3 class="wp-block-heading">ChartDataset and Chart Modes</h3>



<p>I already showed you that a chart set to Line or Bar only displays data sets created from the ChartLinearDataset class. A similar rule applies when the chart is set to other Modes. For example, Pie, Doughnut, PolarArea or Radar charts only display data sets created from the ChartCircularDataset class.</p>



<figure class="wp-block-image is-style-default"><img loading="lazy" decoding="async" width="1024" height="232" src="https://blog.xojo.com/wp-content/uploads/2023/02/CircularDataset-1024x232.png" alt="" class="wp-image-11325" srcset="https://blog.xojo.com/wp-content/uploads/2023/02/CircularDataset-1024x232.png 1024w, https://blog.xojo.com/wp-content/uploads/2023/02/CircularDataset-300x68.png 300w, https://blog.xojo.com/wp-content/uploads/2023/02/CircularDataset-768x174.png 768w, https://blog.xojo.com/wp-content/uploads/2023/02/CircularDataset-1536x349.png 1536w, https://blog.xojo.com/wp-content/uploads/2023/02/CircularDataset-2048x465.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<ul class="wp-block-list">
<li>In the same vein, Scatter and Bubble charts only display data sets created from the ChartScatteredDataset class.</li>
</ul>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="300" height="277" src="https://blog.xojo.com/wp-content/uploads/2023/02/Scatter-Bubble-300x277.png" alt="" class="wp-image-11326" srcset="https://blog.xojo.com/wp-content/uploads/2023/02/Scatter-Bubble-300x277.png 300w, https://blog.xojo.com/wp-content/uploads/2023/02/Scatter-Bubble-1024x945.png 1024w, https://blog.xojo.com/wp-content/uploads/2023/02/Scatter-Bubble-768x709.png 768w, https://blog.xojo.com/wp-content/uploads/2023/02/Scatter-Bubble.png 1330w" sizes="auto, (max-width: 300px) 100vw, 300px" /></figure>
</div>


<h3 class="wp-block-heading">DesktopChart and MobileChart, additional Properties</h3>



<p>DesktopChart and MobileChart offer additional customisation properties. For example, you can set the font, font size and font color for the title, legend, labels and values on the Y axis.</p>



<p>When setting the maximum font size used for the drawing of the Y axis values based on the chart control instance size (height), if the height of the control is not enough to display the values at the specified font size, it automatically adjusts.</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="484" src="https://blog.xojo.com/wp-content/uploads/2023/02/ChartFontSize-1024x484.png" alt="" class="wp-image-11327" srcset="https://blog.xojo.com/wp-content/uploads/2023/02/ChartFontSize-1024x484.png 1024w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartFontSize-300x142.png 300w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartFontSize-768x363.png 768w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartFontSize-1536x727.png 1536w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartFontSize-2048x969.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p>Other properties to further customize the look of the chart include BackgroundColor and GridColor.</p>



<p><em>Tip: You may want to set the color to Color.Clear if you want your charts to be drawn or &#8220;visible&#8221;, like if you plan to layout the chart control on top of other UI controls.</em></p>



<p>In addition, you can control whether or not to display that popup that shows the underlying value as the user moves the cursor (or while dragging their finger, on iOS). This is done through the AllowPopover property (True, by default).</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="840" height="392" src="https://blog.xojo.com/wp-content/uploads/2023/02/ChartPopoverCustom.png" alt="" class="wp-image-11328" srcset="https://blog.xojo.com/wp-content/uploads/2023/02/ChartPopoverCustom.png 840w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartPopoverCustom-300x140.png 300w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartPopoverCustom-768x358.png 768w" sizes="auto, (max-width: 840px) 100vw, 840px" /></figure>
</div>


<p>Set the background and text color in the Popover using the PopoverBackgroundColor and PopoverTextColor properties. These expect a ColorGroup instance, so they can adjust when the control is in Light or Dark Mode.</p>



<h3 class="wp-block-heading">Getting informed</h3>



<p>As you may expect from their WebChart counterpart, DesktopChart and MobileChart offer a Pressed event handler to receive the index and dataset instance over which the user clicked/tapped.</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="206" src="https://blog.xojo.com/wp-content/uploads/2023/02/ChartPressed-1024x206.png" alt="" class="wp-image-11329" srcset="https://blog.xojo.com/wp-content/uploads/2023/02/ChartPressed-1024x206.png 1024w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartPressed-300x60.png 300w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartPressed-768x154.png 768w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartPressed.png 1194w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p>Because the chart control can handle different ChartDatasets you&#8217;ll probably want to cast the received ChartDataset instance received in the Pressed handler to the right one before proceeding with any actions that are not common to all kind of ChartDatasets.</p>



<h3 class="wp-block-heading">Draw it!</h3>



<p>You can call the DrawInto method on a chart, provide the expected graphic context and also the left and top values to proceed with the drawing. For example, this is what a DesktopChart looks like when drawn on a Picture of the same size:</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="560" height="322" src="https://blog.xojo.com/wp-content/uploads/2023/02/ToPicture.png" alt="" class="wp-image-11330" srcset="https://blog.xojo.com/wp-content/uploads/2023/02/ToPicture.png 560w, https://blog.xojo.com/wp-content/uploads/2023/02/ToPicture-300x173.png 300w" sizes="auto, (max-width: 560px) 100vw, 560px" /></figure>
</div>


<p>It is also possible to render the chart to PDF in a vectorial way using the AddChart method on a PDFDocument instance. The parameters this method expects are the chart instance itself, the X and Y values (where it will be placed in the current PDF page), and the width and height values for the rendering.</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="573" src="https://blog.xojo.com/wp-content/uploads/2023/02/ChartToPDF-1024x573.png" alt="" class="wp-image-11331" srcset="https://blog.xojo.com/wp-content/uploads/2023/02/ChartToPDF-1024x573.png 1024w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartToPDF-300x168.png 300w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartToPDF-768x429.png 768w, https://blog.xojo.com/wp-content/uploads/2023/02/ChartToPDF.png 1452w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p>For example, this code will create a PDF file in the Desktop with the same height value of the chart instance, with the width set to the width of the page, minus the margins:</p>



<pre class="wp-block-code xojo"><code><code>Var d As New PDFDocument</code>
<code><span style="font-family: inherit; font-size: inherit;">Var g As Graphics = d.Graphics</span>
d.AddChart(chart1, 20, 20, g.Width-40, chart1.Height )
d.Save(SpecialFolder.Desktop.Child("ChartPDF.PDF"))</code></code></pre>



<h3 class="wp-block-heading">In summary</h3>



<p>As you can see, now it is possible to add Graphical Charts to your Desktop and iOS projects with the same ease and in the same way it is already possible on web projects, plus some more customization options. Watch a <a href="https://youtu.be/zO_UNDlERwE">quick video</a> on this topic. No license is required to learn, develop and test your projects in the latest Xojo release! <a href="https://xojo.com/download/">Download Xojo</a> 2023r1 today!</p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>PDFTable from a RowSet</title>
		<link>https://blog.xojo.com/2023/01/17/pdftable-from-a-rowset/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Tue, 17 Jan 2023 16:00:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Desktop]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Eddie&#039;s Electronics]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[Rapid Application Development]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Tables]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=11146</guid>

					<description><![CDATA[Xojo recently introduced the ability to add (aka draw) tables in PDFDocument using the PDFTable class and the PDFTableDataSource class interface together. Perhaps you already know how to use it, but what if you want to add a table using data from a RowSet? Continue reading and I will show you a technique that will have you doing just that!]]></description>
										<content:encoded><![CDATA[
<p>Xojo recently introduced the ability to add (aka draw) tables in <a href="https://documentation.xojo.com/api/pdf/pdfdocument.html#pdfdocument">PDFDocument</a> using the <a href="https://documentation.xojo.com/api/pdf/pdftable.html#pdftable">PDFTable</a> class and the <a href="https://documentation.xojo.com/api/pdf/pdftabledatasource.html#pdftabledatasource">PDFTableDataSource</a> class interface together. Perhaps you already know how to use it, but what if you want to add a table using data from a <a href="https://documentation.xojo.com/api/databases/rowset.html#rowset">RowSet</a>? Continue reading and I will show you a technique that will have you doing just that!</p>



<span id="more-11146"></span>



<p>But before we dive into the code,&nbsp;this example project requires the &#8220;EddiesElectronics.sqlite&#8221; SQLite database file. You can find the Eddie&#8217;s Electronics example, along with the other example projects provided with Xojo, in the Examples section of the Project Chooser. Because I am such a kind person, you can also <a href="https://drive.google.com/file/d/1zts_ZL2ZQujW7fWD1m2qr_XpQGq3dbHD/view?usp=share_link">download it directly from this link</a>.</p>



<p>And, if you want, it is also possible to download the resulting <a href="https://drive.google.com/file/d/1Z5Eurwxm7UXlCLU_aj270SNKnlDmpT7Z/view?usp=share_link">Xojo Project file (for Desktop) from this link</a>.</p>



<p>I&#8217;m pretty sure you will be able to adapt the example project so it works for you with other databases too!</p>



<figure class="wp-block-image is-style-default"><img loading="lazy" decoding="async" width="809" height="1024" src="https://blog.xojo.com/wp-content/uploads/2023/01/GeneratedPDF-809x1024.png" alt="" class="wp-image-11149" srcset="https://blog.xojo.com/wp-content/uploads/2023/01/GeneratedPDF-809x1024.png 809w, https://blog.xojo.com/wp-content/uploads/2023/01/GeneratedPDF-237x300.png 237w, https://blog.xojo.com/wp-content/uploads/2023/01/GeneratedPDF-768x972.png 768w, https://blog.xojo.com/wp-content/uploads/2023/01/GeneratedPDF-1214x1536.png 1214w, https://blog.xojo.com/wp-content/uploads/2023/01/GeneratedPDF.png 1342w" sizes="auto, (max-width: 809px) 100vw, 809px" /></figure>



<h3 class="wp-block-heading">Helper class to the rescue!</h3>



<p>All the work of drawing the table in the PDF document will be done by a helper class. That is, a class that we are going to use to &#8220;delegate&#8221; the work. With Xojo open and a new Desktop project created, the first thing we are going to do is add a new Class to the project (Insert &gt; Class).</p>



<p>With the added Class selected in the Navigator, go to the associated Inspector Panel and use the following values:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> PDFRenderer</li>



<li><strong>Interfaces:</strong> Click on the &#8220;Choose&#8221; button and select the PDFTableDataSource class interface</li>
</ul>



<p>The just added Class will be populated with all the methods defined by the PDFTableDataSource class interface. Do not worry about them now.</p>



<p>Next, let&#8217;s add a few properties to our PDFRenderer class:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> data</li>



<li><strong>Type:</strong> RowSet</li>



<li><strong>Scope:</strong> Protected</li>
</ul>



<ul class="wp-block-list">
<li><strong>Name:</strong> document</li>



<li><strong>Type:</strong> PDFDocument</li>



<li><strong>Scope:</strong> Protected</li>
</ul>



<ul class="wp-block-list">
<li><strong>Name:</strong> DrawingFromRowSet</li>



<li><strong>Type:</strong> Boolean</li>



<li><strong>Scope:</strong> Protected</li>
</ul>



<ul class="wp-block-list">
<li><strong>Name:</strong> Headers()</li>



<li><span style="font-size: revert;"><strong>Type:</strong> String</span></li>



<li><span style="font-size: revert;"><strong>Scope:</strong> Protected</span></li>
</ul>



<p>We are going to use the DrawingFromRowSet as a flag, so the PDFRenderer knows when the table is going to be created from a RowSet. You could use any other data source, you are limited to RowSet. That&#8217;s just something you will need to implement yourself! Take it as an exercise.</p>



<p>Next, add a new Method to the PDFRenderer class (while still selected in the Navigator) using the following values in the associated Inspector Panel:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> Constructor</li>



<li><strong>Parameters:</strong> document As PDFDocument</li>



<li><strong>Scope:</strong> Public</li>
</ul>



<p>And type the following line of code in the associated Code Editor:</p>



<pre class="wp-block-preformatted xojo"><code>Self.Document = document</code></pre>



<p>Yep, it is truly that simple. Assign the received PDFDocument object to the &#8220;Document&#8221; property of the object created from the PDFRenderer class.</p>



<p>Add a second method using the following values:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> DrawTable</li>



<li><strong>Parameters:</strong> rs As RowSet, headers() As String</li>



<li><strong>Scope:</strong> Public</li>
</ul>



<p>And type the following code in the associated Code Editor:</p>



<pre class="wp-block-preformatted"><code>// This is the method we call on the Class to draw
// a table on a PDFDocument based on a RowSet

If document &lt;&gt; Nil And rs &lt;&gt; Nil Then

  // Assign the received RowSet to the "Data" property
  Self.data = rs

  // Assign the received headers to the "Headers" property
  Self.Headers = Headers

  // Hey! We are going to create a table from a RowSet
  // so we use a Boolean property as a flag for that
  // (Yeah, we can do it using other techniques, but this
  // is easy enough for this purpose…&nbsp;while leave this
  // helper class "open" enough for drawing tables based on other
  // data sources).
  Self.DrawingFromRowSet = True

  // How many columns are we going to draw?
  // Well… as many as columns in the RowSet.
  Var totalColumns As Integer = rs.ColumnCount

  // This is going to be the "drawable area" on the page
  // for the table = total page width less the left and right margins
  Var totalWidth As Double = document.Graphics.Width - 40 // 40 = 20 points left/right margins

  // Creating the PDFTable object here!
  Var table As New PDFTable

  // We want to repeat the headers on every page
  table.HasRepeatingHeader = True

  // Setting the column count for the table
  table.ColumnCount = totalColumns

  // …and the width for every column.
  table.ColumnWidths = CalculateColumnWidths(TotalWidth, totalColumns)

  // The object from this class will be the responsible
  // for handling all the methods associated with the
  // PDFTableDataSouce Class Interface
  table.DataSource = Self

  // Setting the Top and Bottom margins for the drawing
  // of the table on every PDF page
  table.TopMargin = 20
  table.BottomMargin = 20

  // …and finally we instruct the PDFDocument object
  // to draw the table!
  document.AddTable(table, 20, 0)

  // Lastly, clearing the flag
  Self.DrawingFromRowSet = False

End If</code></pre>



<p>As you can see here, we are calling the &#8220;CalculateColumnWidths&#8221; method in order to get the expected string for the column widths for the PDFTable.ColumnWidths property; so add a new method to the PDFRenderer class using the following values:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> CalculateColumnWidths</li>



<li><strong>Parameters:</strong> TotalWidth As Double, NumberOfColumns As Double</li>



<li><strong>Return Type:</strong> String</li>



<li><strong>Scope:</strong> Protected</li>
</ul>



<p>And type the following snippet of code in the associated Code Editor:</p>



<pre class="wp-block-preformatted"><code>Var ColumnWidth As Integer = TotalWidth / NumberOfColumns
Var s() As String

For n As Integer = 0 To NumberOfColumns-1
  s.Add(Str(ColumnWidth))
Next

Return String.FromArray(s, ",")</code></pre>



<h3 class="wp-block-heading">PDFTableDataSource Methods with RowSet data!</h3>



<p>Let&#8217;s fill the required methods from the PDFTableDataSource class interface so they work in combination with the received RowSet.</p>



<h4 class="wp-block-heading">AddNewRow Method</h4>



<p>Add this snippet of code for the &#8220;AddNewRow&#8221; method:</p>



<pre class="wp-block-preformatted"><code>If DrawingFromRowSet And data &lt;&gt; Nil Then

  // We are going to draw as many rows as rows are in the
  // "data" rowset
  Return rowCount &lt;&gt; data.RowCount

End If</code></pre>



<p>As you can see, that fragment of code will only run when both conditions are meet. That is, when the &#8220;DrawingFromRowSet&#8221; is set to True and the &#8220;data&#8221; property is set to a not niled RowSet. If this is the case, we then instruct our PDFTable to set the number of rows to be drawn to the same number of rows in the RowSet.</p>



<h4 class="wp-block-heading">Completed Method</h4>



<p>This is the method that will be called once the drawing of the PDFTable has been completed. We will use it to draw the page numbers at the bottom of every page in the PDFDocument. As you probably already know, it is really easy to change the active graphic context to a given page of the PDF document using the CurrentPage property, so we will use that to iterate every one of our PDF document pages, adding the page number to it as a footer.</p>



<p>This is the snippet of code responsible for doing just that:</p>



<pre class="wp-block-preformatted"><code>// This method is called once the table has been drawn
// so let's "print" the page number on every page
// of the PDF Document

Static pageNumber As String = "Page: "

If document &lt;&gt; Nil Then
  Var g As Graphics = document.Graphics

  For n As Integer = 1 To document.PageCount
    document.CurrentPage = n
    g.DrawText(pageNumber + Str(n), g.Width - g.TextWidth(pageNumber+Str(n))-20, g.Height-g.FontAscent)
  Next

End If</code></pre>



<h4 class="wp-block-heading">HeaderHeight Method</h4>



<p>This is the method called so we can set the PDFTable the desired height for the drawing of the Header. In this case we are going to use a fixed value: 20 points. The code for that method is:</p>



<pre class="wp-block-preformatted"><code>// Fixed header height
Return 20</code></pre>



<h4 class="wp-block-heading">PaintCell Method</h4>



<p>This is the method responsible for drawing every cell of the PDFTable. It receives as parameters the Graphic context for a particular cell (so its origin is at 0,0) and the row and column values corresponding for such cell.</p>



<p>In this case, draw the outline of a rectangle for the cell plus the text itself retrieved from the RowSet based on the received Column value. The text will be draw vertically centered in the cell:</p>



<pre class="wp-block-preformatted"><code>If DrawingFromRowSet And data &lt;&gt; Nil Then
  // Drawing the outer rectangle for the cell
  g.DrawRectangle(0, 0, g.Width, g.Height)

  // retrieving the text to be drawn from the RowSet,
  // using the column parameter for that.
  Var s As String = data.ColumnAt(column)

  // Centering vertically the text on the table cell
  // while the X offset is fixed at 5 points.
  g.DrawText(s, 5, g.Height / 2 + g.FontAscent / 2)

  // Have we drawn all the columns for this row?
  If column = data.ColumnCount - 1 Then

    // if that is the case, then move to the next row
    // in the RowSet!
    data.MoveToNextRow
  End If

End If</code></pre>



<h4 class="wp-block-heading">PaintHeaderContent Method</h4>



<p>This is the method called in order to draw the Header of the table itself. It is a more simple version of the previous method. In this case, the text will be centered both vertically and horizontally on every header cell:</p>



<pre class="wp-block-preformatted"><code>If column &lt;= Self.Headers.LastIndex Then

  Var s As String = headers(column)
  g.DrawingColor = Color.Black
  g.FillRectangle(0, 0, g.Width, g.Height)
  g.DrawingColor = Color.White
  g.DrawText(s, g.Width / 2 - g.TextWidth(headers(column)) / 2, g.Height / 2 + g.FontAscent / 2)

End If</code></pre>



<h4 class="wp-block-heading">RowHeight Method</h4>



<p>As it happen with the HeaderHeight method, this is the method called to set the height for a given row. As we did for the HeaderHeight method we are going to use a fixed value of 20 points, so type the following line of code in the associated Code Editor:</p>



<pre class="wp-block-preformatted"><code>Return 20</code></pre>



<h3 class="wp-block-heading">Testing The PDFRenderer class</h3>



<p>In order to test our PDFRenderer class in combination with a RowSet object, we need to do some additional work. First, select the Window1 window in the project Navigator and add a property using the following values:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> db</li>



<li><strong style="font-size: revert;">Type:</strong><span style="font-size: revert;"> SQLiteDatabase</span></li>



<li><strong style="font-size: revert;">Scope:</strong><span style="font-size: revert;"> Private</span></li>
</ul>



<p>Next, click the Window1 window in the Navigator so it is displayed in the Layout Editor. Then, drag a DesktopLabel from the Library and drop it on the left/top edge of the layout observing the aligning guides so it leaves the expected margin over the left and top edges of the Window. Use the dragging handlers of the DesktopLabel on the layout to resize it to the maximum width (once again, less the expected margins). Use the following values in the associated Inspector Panel:</p>



<ul class="wp-block-list">
<li><strong>Locking:</strong> Left, Top and Right locked. Bottom, unlocked.</li>



<li><strong>Multiline:</strong> on.</li>



<li><strong>Text:</strong> This example project needs to use the EddiesElectronics.sqlite database file. Click on the button in order to select it!</li>
</ul>



<p>The layout at this point should look like this:</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="331" src="https://blog.xojo.com/wp-content/uploads/2023/01/Screenshot-2023-01-10-at-15.17.36-1024x331.png" alt="" class="wp-image-11147" srcset="https://blog.xojo.com/wp-content/uploads/2023/01/Screenshot-2023-01-10-at-15.17.36-1024x331.png 1024w, https://blog.xojo.com/wp-content/uploads/2023/01/Screenshot-2023-01-10-at-15.17.36-300x97.png 300w, https://blog.xojo.com/wp-content/uploads/2023/01/Screenshot-2023-01-10-at-15.17.36-768x248.png 768w, https://blog.xojo.com/wp-content/uploads/2023/01/Screenshot-2023-01-10-at-15.17.36.png 1274w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p>Now, drag a DesktopButton from the Library and drop it below the previous Label so it is horizontally centered, using the following values in the associated Inspector Panel:</p>



<ul class="wp-block-list">
<li><strong>Caption:</strong> Select EddiesElectronics database file</li>
</ul>



<p>The finished layout should look like this:</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="747" src="https://blog.xojo.com/wp-content/uploads/2023/01/Screenshot-2023-01-10-at-15.19.13-1024x747.png" alt="" class="wp-image-11148" srcset="https://blog.xojo.com/wp-content/uploads/2023/01/Screenshot-2023-01-10-at-15.19.13-1024x747.png 1024w, https://blog.xojo.com/wp-content/uploads/2023/01/Screenshot-2023-01-10-at-15.19.13-300x219.png 300w, https://blog.xojo.com/wp-content/uploads/2023/01/Screenshot-2023-01-10-at-15.19.13-768x561.png 768w, https://blog.xojo.com/wp-content/uploads/2023/01/Screenshot-2023-01-10-at-15.19.13.png 1422w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p>Double click the button to add the &#8220;Pressed&#8221; Event Handler. Then, add the following code in the associated Code Editor:</p>



<pre class="wp-block-preformatted"><code>Try

  // Assigning SQLite object to property
  db = New SQLiteDatabase

  // Setting the database file to the SQLite object
  db.DatabaseFile = FolderItem.ShowOpenFileDialog(".sqlite")

  // Just a simple check to see if this is the expected
  // file based on the name = "EddiesElectronics.sqlite"

  If db.DatabaseFile = Nil Or db.DatabaseFile.Name &lt;&gt; "EddiesElectronics.sqlite" Then Return

  //…and "connecting" to it!
  db.Connect

  // Let's select all the rows from the Customers table
  Var rs As RowSet = db.SelectSQL("SELECT FirstName,LastName,Address FROM Customers")

  // Creating a new PDFDocument Instance
  Var d As New PDFDocument

  // Creating the PDFTable renderer helper object (we pass the PDFDocument object to it in the Constructor)
  Var PDFRender As New PDFRenderer(d)

  // These will be the headers drawn in the Table
  Var headers() As String = Array("Name", "Surname", "Address")

  // And let's instruct the PDFTable renderer helper to draw the table
  // based in the SQLite database rowset we got in the previous step
  PDFRender.DrawTable(rs, headers)

  // …and save the resulting PDF File to the Desktop
  Var f As FolderItem = SpecialFolder.Desktop.Child("TableFromRowSet.pdf")

  If f &lt;&gt; Nil Then
    d.Save(f)
    f.Open
  End If

Catch e As DatabaseException
  System.DebugLog(e.Message)
Catch e As NilObjectException
  System.DebugLog(e.Message)
End Try</code></pre>



<p>As you can see, all this does is create a new SQLiteDatabase object and assign it to the &#8220;db&#8221; property. Then, we set the &#8220;DataBaseFile&#8221; property of that object to the file selected by the user. The code will do a simple check to see if the selected file is the expected &#8220;EddiesElectronics&#8221; database file. If that is the case, then it will connect to the database, getting a RowSet from a simple query that retrieves the &#8220;name&#8221;, &#8220;surname&#8221; and &#8220;address&#8221; columns from the &#8220;Customers&#8221; database table.</p>



<p>After creating the PDFDocument instance, the code creates a new instance from our PDFRenderer class and calls the &#8220;DrawTable&#8221; method on that object passing along both the RowSet and the Headers we want to use for drawing the table.</p>



<p>Lastly, the PDFDocument will be saved to disk and opened in the by default PDF viewer app.</p>



<p>Run the app, select the &#8220;EddiesElectronics&#8221; SQLite database file&nbsp;and the resulting PDF file will be opened after a few seconds. It will display the table generated from a RowSet data source!</p>



<h3 class="wp-block-heading">In Summary</h3>



<p>It is quite possible to draw tables in a PDFDocument when the data to render comes from a RowSet. Nearly everything was done through the use of a helper class. As always, this can be improved in several ways! For example, we are using a fixed height for every row of the table, but in a more realistic scenario may be using variable heights for the table rows based in the height / amount of data to be drawn. That is something that is doable too!</p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>PDFDocument: Margins, Merging in a Table and the new Completed method</title>
		<link>https://blog.xojo.com/2022/12/13/pdfdocument-margins-merging-in-a-table-and-the-new-completed-method/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Tue, 13 Dec 2022 14:33:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Desktop]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Multi-Platform Development]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=11036</guid>

					<description><![CDATA[Xojo 2022r3 included the ability to easily add tables to PDF documents created with Xojo. Now, starting with Xojo 2022r4, this feature has been improved so you can to merge the cells in table's row! Additionally, you can now  set a page's upper and lower margins and get informed when the table has finished drawing itself. Continue reading to learn how to do all these things!]]></description>
										<content:encoded><![CDATA[
<p>Xojo 2022r3 included the ability to easily add tables to PDF documents created with Xojo. Now, starting with Xojo 2022r4, this feature has been improved so you can to merge the cells in table&#8217;s row! Additionally, you can now set a page&#8217;s upper and lower margins and get informed when the table has finished drawing itself. Continue reading to learn how to do all these things!</p>



<span id="more-11036"></span>



<p>In order to merge cells in a table&#8217;s row, the PDFTableDataSource class interface includes a new method: MergeCellsForRow(row As Integer, ByRef CellsToMerge() As CellRange) As Boolean. This method will be called for every table row to be drawn so you can provide the range of cells to merge as a CellRange instance.</p>



<p>For example, the following statement will merge all the cells for a row in a five column table:</p>



<pre class="wp-block-preformatted"><code>CellsToMerge.Add New CellRange(0,4)</code></pre>



<p>Where CellsToMerge is an array parameter received by reference. So, if we apply the previous sentence to every even row in the table:</p>



<pre class="wp-block-preformatted"><code>If row Mod 2 = 0 Then
  CellsToMerge.Add New CellRange(0,4)
  Return True
End If</code></pre>



<p>We will get the following PDF as result (based on the PDF table example project):</p>



<figure class="wp-block-image is-style-default"><img loading="lazy" decoding="async" width="801" height="1024" src="https://blog.xojo.com/wp-content/uploads/2022/12/MergedCells-801x1024.png" alt="" class="wp-image-11037" srcset="https://blog.xojo.com/wp-content/uploads/2022/12/MergedCells-801x1024.png 801w, https://blog.xojo.com/wp-content/uploads/2022/12/MergedCells-235x300.png 235w, https://blog.xojo.com/wp-content/uploads/2022/12/MergedCells-768x982.png 768w, https://blog.xojo.com/wp-content/uploads/2022/12/MergedCells-1202x1536.png 1202w, https://blog.xojo.com/wp-content/uploads/2022/12/MergedCells.png 1330w" sizes="auto, (max-width: 801px) 100vw, 801px" /></figure>



<h2 class="wp-block-heading">Top and Bottom Margins</h2>



<p>In addition, the PDFTable class now has two new properties: TopMargin As Double and BottomMargin As Double. As you can guess these will let you set the top and bottom margins for the table when it is added to the PDF document pages; specially interesting when the table is going to spread several pages because you won&#8217;t need to do any maths in order to know when a new page needs to be added to the document, PDFDocument will take care of it based on the provided values plus the height value of every row to be drawn!</p>



<h2 class="wp-block-heading">Hey mate, the table has been drawn!</h2>



<p>Lastly, we also added the Completed(x As Double, y As Double) method to the PDFTableDataSource class Interface, so your code can know the right spot at which the table has finished drawing itself. This is specially interesting when the table spreads several pages, so you can get the last X and Y coordinates of the table drawing in order you can continue adding new content to the PDF page right after it!</p>



<p>For example, the following code in the Completed method of our example will render the &#8220;Drawing Table Completed!&#8221; text in the last added page, just below the drawing of the table, adding 20 points to the received Y value and using the same X value so the left margin for the text is the same that the one used to draw the table:</p>



<figure class="wp-block-image is-style-default"><img loading="lazy" decoding="async" width="1024" height="576" src="https://blog.xojo.com/wp-content/uploads/2022/12/TableCompleted-1024x576.png" alt="" class="wp-image-11038" srcset="https://blog.xojo.com/wp-content/uploads/2022/12/TableCompleted-1024x576.png 1024w, https://blog.xojo.com/wp-content/uploads/2022/12/TableCompleted-300x169.png 300w, https://blog.xojo.com/wp-content/uploads/2022/12/TableCompleted-768x432.png 768w, https://blog.xojo.com/wp-content/uploads/2022/12/TableCompleted.png 1302w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading">In Summary</h2>



<p>These additions give you more control when drawing the tables to your PDFDocuments: setting both the upper and lower margins for the page, getting informed when the table has finished drawing itself, and the ability to merge cells independently on every row of the table!</p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Adding Tables to PDFDocument</title>
		<link>https://blog.xojo.com/2022/10/12/adding-tables-to-pdfdocument/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Wed, 12 Oct 2022 13:45:45 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Desktop]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Xojo Cloud]]></category>
		<category><![CDATA[Multi-Platform Development]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[Rapid Application Development]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=10756</guid>

					<description><![CDATA[Starting with Xojo 2022r3 it is possible to create and add tables to PDF documents using Xojo&#8217;s PDFTable class and the PDFTableDataSource class interface. Among&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Starting with Xojo 2022r3 it is possible to create and add tables to PDF documents using Xojo&#8217;s PDFTable class and the PDFTableDataSource class interface. Among other things, your code will not need to be in charge of calculating rows sizes in order to decide if it needed to add a new page or not, or even complex calculations in order to draw the content on every cell of every row/column pair in the table.</p>



<p>You can download the example project <a href="https://www.dropbox.com/s/bkdpoem0vn3vqcx/PDFTable-Example.zip?dl=1">from this link</a>.</p>



<h3 class="wp-block-heading">Features of Tables in PDFDocument</h3>



<p>The main features available with tables in PDFDocument are:</p>



<ul class="wp-block-list"><li>PDFTable / PDFTableDataSource is compatible with Desktop, Web, Console and RaspberryPi projects</li><li>Variable height rows</li><li>Automatically add new pages to the PDF</li><li>The ability to repeat (or not) the table header at the start of every new page added</li></ul>



<p>In order to achieve this, the PDFTable class works side by side with the PDFTableDataSource class interface. This class interface declares the methods that will be called by a given PDFTable instance in order to generate the table on the fly.</p>



<ul class="wp-block-list"><li>PDFTableDataSource</li></ul>



<p>Because it is a class interface, you will be able to add it to any window/web page or any class/subclass you  create, so it can work as the provider of the data in the drawing of a given PDF table.</p>



<p>The PDFTableDataSource has these five methods:</p>



<ul class="wp-block-list"><li><strong>AddNewRow(rowCount As Integer) As Boolean</strong>&#8211; The rowCount parameter contains the value of the rows already added to the table. Returning True from this method will add a new row to the table; otherwise it will end the creation of the associated table.</li><li><strong>HeaderHeight As Double</strong>&#8211; In the implementation of this method you will set the height value used in order to draw the table header.</li><li><strong>PaintCell(g As Graphics, row As Integer, column As Integer)</strong>&#8211; This is the method called by the PDFTable instance in order to draw the cell for the row/column pair stored in the associated parameters. The method receives its own graphic context in the &#8216;g&#8217; variable, so you can use any of the supported methods and properties of the Graphic class to draw the contents in the table cell.</li><li><strong>PaintHeaderContent(g As Graphics, column As Integer)</strong>&#8211; This is the method called by the PDFTable instance every time it needs to draw the header of the table. As you can see, it receives as parameters the column number and its own graphic context.</li><li><strong>RowHeight As Double</strong>&#8211; This is the method called by the PDFTable instance so your code can set the height for the current row.</li></ul>



<h3 class="wp-block-heading">PDFTable</h3>



<p>This is a really simple class exposing a total of four properties:</p>



<ul class="wp-block-list"><li><strong>ColumnCount As Integer</strong>&#8211; This is the property that sets the number of columns for the table to be drawn.</li><li><strong>ColumnWidths As String</strong>&#8211; This is the property that sets as a string the width of every column in the table, separated by the comma character.</li><li><strong>DataSource As PDFTableDataSource</strong>&#8211; This is the property that sets the object acting as the data source object for the table. Remember that such an object needs to implement the methods declared in the PDFTableDataSource class interface.</li><li><strong>HasRepeatingHeader As Boolean</strong>&#8211; Use this property to instruct the PDFTable instance if it needs to repeat the header on every new page that is added to the document as the table is generated.</li></ul>



<p>For example, the following fragment of code will create a table with a total of three columns that have the same size. The table will be drawn horizontally centered in the page. The object acting as the data source for the table will be the same where this snippet of code has been added, that is: &#8216;Self&#8217;:</p>



<pre class="wp-block-preformatted"><code>Var d As New PDFDocument

Var tTable As New PDFTable
tTable.ColumnCount = 3
tTable.ColumnWidths = "150,150,150"
tTable.DataSource = Self
tTable.HasRepeatingHeader = True</code></pre>



<p>The way to add a PDFTable instance to the current page of the PDF document is through the AddTable(table As PDFTable, x As Double, y As Double) method; for example:</p>



<pre class="wp-block-preformatted"><code>Var x As Double = d.PageWidth/2 - 450/2

d.addTable(tTable,x,20)</code></pre>



<h3 class="wp-block-heading">&nbsp;</h3>



<h3 class="wp-block-heading">PDFTable in Practice</h3>



<p>In this example, you can see how to create a PDF document with a table added to it (horizontally centered on the pages). This table will have three columns equally sized and a total of 100 rows with a variable —random— height—, and giving the option to the user so they can choose to repeat the table header on every new page added to the document or not.</p>



<p>The cell contents of the table will be chosen randomly, varying between filling the cell with a random color, drawing text with the row and column numbers for the cell, rendering an image that has been added to the project, or keeping the cell empty.</p>



<p>Create a new Desktop project. With the Window1 selected in the Navigator, click on the &#8220;Choose…&#8221; button found in the associated Inspector Panel under the Interface section. This action will open a new window displaying all the available Class Interfaces. Select the PDFTableDataSource entry and confirm the selection click the Ok button.</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="927" height="1024" src="https://blog.xojo.com/wp-content/uploads/2022/10/Selector-PDFDataTableSource-927x1024.png" alt="" class="wp-image-10757" srcset="https://blog.xojo.com/wp-content/uploads/2022/10/Selector-PDFDataTableSource-927x1024.png 927w, https://blog.xojo.com/wp-content/uploads/2022/10/Selector-PDFDataTableSource-272x300.png 272w, https://blog.xojo.com/wp-content/uploads/2022/10/Selector-PDFDataTableSource-768x848.png 768w, https://blog.xojo.com/wp-content/uploads/2022/10/Selector-PDFDataTableSource.png 1012w" sizes="auto, (max-width: 927px) 100vw, 927px" /></figure>
</div>


<p>As result, the methods declared by the PDFTableDataSource are now added to the Window1 item.</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="505" height="270" src="https://blog.xojo.com/wp-content/uploads/2022/10/PDFTableDataSource-Methods.png" alt="" class="wp-image-10758" srcset="https://blog.xojo.com/wp-content/uploads/2022/10/PDFTableDataSource-Methods.png 505w, https://blog.xojo.com/wp-content/uploads/2022/10/PDFTableDataSource-Methods-300x160.png 300w" sizes="auto, (max-width: 505px) 100vw, 505px" /></figure>
</div>


<p>Grab a CheckBox control from the Library and drop it in the upper-left corner of the window in the Layout Editor. Use the associated Inspector Panel to change the following values:</p>



<ul class="wp-block-list"><li><strong>Name:</strong> RepeatHeaderCB</li><li><strong>Visual State:</strong> Checked</li></ul>



<p>In order to complete this basic user interface, drag a Button control from the Library and drop it in the upper-right corner of the window in the Layout Editor. With Button1 selected in the Navigator, choose the Add to &#8220;Button1&#8221; &gt; Event Handler…&nbsp;option from the contextual menu. Next, select the Pressed event from the resulting window and confirm the selection so it is added to the Window1 object.</p>



<p>With the Pressed event selected in the Navigator, add the following fragment of code in the associated Code Editor:</p>



<pre class="wp-block-preformatted"><code>Var d As New PDFDocument

Var tTable As New PDFTable
tTable.ColumnCount = 3
tTable.ColumnWidths = "150,150,150"
tTable.DataSource = Self
tTable.HasRepeatingHeader = RepeatHeaderCB.Value

Var x As Double = d.PageWidth/2 - 450/2

d.addTable(tTable,x,20)

d.Save(SpecialFolder.Desktop.Child("Table.pdf"))</code></pre>



<p>Drop any image you want to use from your computer drive into the Xojo&#8217;s IDE Navigator. Our example uses an image named &#8220;XojoLogo100&#8221;. When adding your own image, you can opt to rename it to the name name used in the code of this example, or changing all the references where &#8220;XojoLogo100&#8221; is referenced to the name of your image.</p>



<p>Now it is time to implement the code in every one of the five methods required by the PDFTableDataSource class interface.</p>



<p>In the AddNewRow method:</p>



<pre class="wp-block-preformatted"><code>Return rowCount &lt; 100 // Our example table has a total of 100 rows.</code></pre>



<p>In the HeaderHeight method:</p>



<pre class="wp-block-preformatted"><code>Return 30 // This is the height for the cells of the header in the table.</code></pre>



<p>In the PaintCell method:</p>



<pre class="wp-block-preformatted"><code>Var rd As New Random

Var option As Integer = rd.InRange(1,4)

Select Case option

Case 1

  Var s As String = "row: " + row.ToString + " column: " + Column.ToString
  Var h As Double = g.Height/2 + g.TextHeight/2
  g.DrawText s,5,h

Case 2

  g.DrawPicture(XojoLogo100,0,0)

Case 3

  g.DrawingColor = Color.RGB(rd.InRange(0,255), rd.InRange(0,255), rd.InRange(0,55))
  g.FillRectangle(2,2,g.Width-4,g.Height-4)

Case 4

 // Empty cell
End Select

g.DrawingColor = Color.Black
g.DrawRectangle 0,0, g.Width,g.Height</code></pre>



<p>And this is the code we will use in order to draw the content of the table Header cells in the PaintHeaderContent:</p>



<pre class="wp-block-preformatted"><code>Var tRandom As New Random

Var c As Color

Select Case Column
Case 0
  c = color.Red
Case 1
  c = Color.Green
Case 2
  c = Color.Blue
End Select

g.DrawingColor = c
g.FillRectangle 0,0,g.Width,g.Height

Var s As String = "Column: " + Column.ToString

Var x, y As Double
x = (g.Width/2) - (g.TextWidth(s)/2)
y = (g.Height/2) + (g.TextHeight/2)

g.DrawingColor = color.Black
g.DrawText s,x, y</code></pre>



<p>Now add the code responsible for setting the height of every new row added to the table in the RowHeight method. As you can see, this value is a random value between 25 and 100 points:</p>



<pre class="wp-block-preformatted"><code>Var rd As New Random

return rd.InRange(25,100)</code></pre>



<h3 class="wp-block-heading">Running the App</h3>



<p>Run the app, click on the button and you will see how a new PDF document named &#8220;Table.pdf&#8221; is created in your computer desktop. The number of pages of the PDF document may vary because the height of the table rows vary on every iteration.</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1018" height="1024" src="https://blog.xojo.com/wp-content/uploads/2022/10/Table-PDF-1018x1024.png" alt="" class="wp-image-10759" srcset="https://blog.xojo.com/wp-content/uploads/2022/10/Table-PDF-1018x1024.png 1018w, https://blog.xojo.com/wp-content/uploads/2022/10/Table-PDF-298x300.png 298w, https://blog.xojo.com/wp-content/uploads/2022/10/Table-PDF-150x150.png 150w, https://blog.xojo.com/wp-content/uploads/2022/10/Table-PDF-768x772.png 768w, https://blog.xojo.com/wp-content/uploads/2022/10/Table-PDF-1527x1536.png 1527w, https://blog.xojo.com/wp-content/uploads/2022/10/Table-PDF-2036x2048.png 2036w" sizes="auto, (max-width: 1018px) 100vw, 1018px" /></figure>
</div>


<p>This time, unselect the checkbox and click the button to create the PDF document again. Now, the table header is only rendered in the first page of the document.</p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>PDFDocument Improvements</title>
		<link>https://blog.xojo.com/2022/10/12/pdfdocument-improvements/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Wed, 12 Oct 2022 13:45:29 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Desktop]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Xojo Cloud]]></category>
		<category><![CDATA[Multi-Platform Development]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[Rapid Application Development]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=10810</guid>

					<description><![CDATA[While PDFTable and PDFDataTableSource ease the way to render tables in your PDF documents on Desktop, Web, Raspberry Pi and Console projects (iOS to come!) are the big new features for PDFDocument in Xojo 2022r3, that's not all that improved. There are additional features added to PDFDocument you might find helpful such as more control while using PDFForm and improvements to dealing with TOC indexes. Learn more about how to get advantage of these additions!]]></description>
										<content:encoded><![CDATA[
<p>While <a href="https://blog.xojo.com/2022/10/12/adding-tables-to-pdfdocument/">PDFTable</a> and PDFDataTableSource ease the way to render tables in your PDF documents on Desktop, Web, Raspberry Pi and Console projects (iOS to come!) and are the big new features for PDFDocument in Xojo 2022r3, that&#8217;s not all that improved. There are additional features added to PDFDocument you might find helpful such as more control while using PDFForm and improvements to dealing with TOC indexes. Learn more about how to get advantage of these additions!</p>



<span id="more-10810"></span>



<h3 class="wp-block-heading">More Control with PDFForm Controls</h3>



<p>It is possible to add forms to your PDF documents using controls as text fields, text areas, list boxes, radio buttons, check boxes, popup menus, combo boxes, etc. Starting with Xojo 2022r3 you&#8217;ll be able to set if the items of PDFComboBox, PDFListBox and PDFPopupMenu are displayed sorted or as they were added using the Boolean IsSorted property.</p>



<p>As for the PDFTextArea and PDFTextField controls, there is a new property AllowSpellChecking so you can set if these will enable spell check or not. And in the case of the PDFTextField, it is also possible to set the HasPassword property so the text typed by the user is substituted in the PDF document with the usual replacement character, hiding what the user is typing from prying eyes!</p>



<h3 class="wp-block-heading">Dealing with TOC Indexes</h3>



<p>Lastly, there are also improvements to dealing with TOC creation in your PDF documents. For example, you can get now the Parent instance from a PDFToc entry through the Parent property; and there are new methods to get all the child items hanging from a PDFTOCEntry —Entries() As PDFTOCEntry()— and to remove existing entries from a PDFTOCEntry instance: PDFTOCEntry.RemoveEntry(ParamArray entries As PDFTOCEntry) and PDFTOCEntry.RemoveEntry(entries() as PDFTOCEntry).</p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>PDFDocument: How To Encrypt PDFs</title>
		<link>https://blog.xojo.com/2022/07/25/pdfdocument-how-to-encrypt-pdfs/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Mon, 25 Jul 2022 13:54:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Desktop]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Xojo Cloud]]></category>
		<category><![CDATA[2022r2]]></category>
		<category><![CDATA[Encryption]]></category>
		<category><![CDATA[PDF]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=10486</guid>

					<description><![CDATA[One of the PDFDocument features added in Xojo 2022r2 is the ability to encrypt PDF files created with Xojo. Continue reading and I will show&#8230;]]></description>
										<content:encoded><![CDATA[
<p>One of the PDFDocument features added in Xojo 2022r2 is the ability to encrypt PDF files created with Xojo. Continue reading and I will show you how.</p>



<span id="more-10486"></span>



<p>Encrypting PDF files with PDFDocument is based in the use of the PDFPermissions class. You&#8217;ll need to create a new instance of the class passing along the &#8220;Owner&#8221; and &#8220;User&#8221; passwords. For example:</p>



<pre class="wp-block-code"><code>Var d As New PDFDocument
Var g As Graphics = d.Graphics

Var p As New PDFPermissions("OwnerPassword","UserPassword")</code></pre>



<p>In addition, you can set other properties for the PDFPermissions instance; all of them are read/write and will be applied by the PDF viewer app for when the document is opened using the &#8220;user&#8221; password.</p>



<ul class="wp-block-list"><li><strong>AllowCopyingContents</strong> is set to <code>False</code> by default. When set to <code>True</code> it will allow copying contents from the PDF, as for example the selected text or image.</li><li><strong>AllowModifyingContents</strong> is set to <code>False</code> by default. When set to <code>True</code> it will all to modify the contents of the protected PDF document.</li><li><strong>AllowPrinting</strong> is se to <code>False</code> by default. When it is set to <code>True</code> it will be possible to print the PDF.</li></ul>



<p>Once the PDFPermissions instance has been created and the desired properties had been set, all you need to do is to assign such instance to the Permissions property for the PDFDocument instance you want to encrypt:</p>



<pre class="wp-block-code"><code>d.Permissions = p</code></pre>



<p>Then, when it&#8217;s saving the document to a file, PDFDocument will encrypt all the streams of data containing sensitive information, as it can be the text or Images rendered on every one of the PDF pages plus the metadata information itself. The used encryption algorithm is AES 128 bits.</p>



<p>That&#8217;s all! You can distinguish an encrypted PDF file from an unencrypted one because, usually, the first one will be displayed with the image of a Lock in the icon. When you open an encrypted PDF in the viewer app you&#8217;ll be asked to type a password. If you enter the passord set to the &#8220;Owner&#8221; user, you&#8217;ll be able to do all the kind of operations allowed by the viewer app, while if you enter the &#8220;User&#8221; password, then the kind of options available will be determined by those set using the PDFPermissions properties.</p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>PDFDocument: New Annotations Types</title>
		<link>https://blog.xojo.com/2022/07/25/pdfdocument-new-annotations-types/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Mon, 25 Jul 2022 13:53:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Desktop]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Xojo Cloud]]></category>
		<category><![CDATA[2022r2]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[Rapid Application Development]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Xojo API 2.0]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=10488</guid>

					<description><![CDATA[The annotations feature on PDFDocument has been significantly extended in the release of Xojo 2022r2. Continue reading to learn about the new annotation types. Currently,&#8230;]]></description>
										<content:encoded><![CDATA[
<p>The annotations feature on PDFDocument has been significantly extended in the release of Xojo 2022r2. Continue reading to learn about the new annotation types.</p>



<p>Currently, Xojo&#8217;s PDFDocument supports the most common type of annotations for PDF &#8211; you know those little yellow boxes displayed like sticky notes on the pages of the PDF document that display their contents when clicked on.</p>



<p>Now with Xojo 2022r2 and later you have more options! And while most of these don&#8217;t look like &#8220;real&#8221; annotations or like something made using the Graphics methods, they will behave as the annotations you are familiar with using in PDF. What I mean by this is that they will display the associated text for the annotation while also allowing the user to Accept/Decline the annotation or interact with them by adding, for example, new replies.</p>



<p>Before reviewing the new options, let me just remind you: The PDF Standard dictates how some features must be implemented for a PDF. After that, it is up to the developers of the PDF viewer app to decide what features are implemented, keep in mind results can vary depending on the PDF viewer you or your user chose to use. As other many things related with PDF files, don&#8217;t expect every PDF viewer apps out there to support or adhere to the annotations outside of the most basic ones.</p>



<p>Adobe is the original creator of the PDF specification and its free PDF viewer, <a href="https://www.adobe.com/acrobat/pdf-reader.html">Acrobat Reader</a> app does support everything Xojo&#8217;s PDFDocument offers.</p>



<h3 class="wp-block-heading">Attaching Files to the PDF</h3>



<p>You&#8217;ll be able to embed any kind of file (except for those based in a Bundle structure) into the PDF document itself, for example an Excel file, a Hi-Res image, etc. Then the user viewing the PDF document will be able to open the attached file clicking in the annotation using whichever PDF Viewer app their computer/device has installed for the attached file format. Because this is an annotation, the user will be able to also edit the annotation or add new replies to it.</p>



<p>This is an example about how to create these kind of annotations:</p>



<pre class="wp-block-code"><code>Var d As New PDFDocument
Var g As Graphics = d.Graphics
Const kContentText As String = "Attached File Annotation: double click on me!"

g.FontSize = 20
g.DrawText(kContentText, 40, 60)

If exampleFile &lt;&gt; Nil Then
  
  // Creating a new EmbeddedSound.
  d.AddEmbeddedFile(exampleFile, 40, 60, g.TextWidth(kContentText), 20)
  
  // Saving the created PDF document to the selected path.
  Var f As FolderItem = FolderItem.ShowSaveFileDialog("","PDFAttachedFile.pdf")
  
  If f &lt;&gt; Nil Then
    
    d.Save(f)
    
  End If
End If
</code></pre>



<p>Here <code>exampleFile</code> is a FolderItem property that has been added to the project and that&#8217;s pointing to the file to embed.</p>



<p>And this is how it looks like in the resulting PDF file:</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="439" src="https://blog.xojo.com/wp-content/uploads/2022/06/AttachedFilePDF-1024x439.png" alt="" class="wp-image-10490" srcset="https://blog.xojo.com/wp-content/uploads/2022/06/AttachedFilePDF-1024x439.png 1024w, https://blog.xojo.com/wp-content/uploads/2022/06/AttachedFilePDF-300x129.png 300w, https://blog.xojo.com/wp-content/uploads/2022/06/AttachedFilePDF-768x329.png 768w, https://blog.xojo.com/wp-content/uploads/2022/06/AttachedFilePDF-1536x658.png 1536w, https://blog.xojo.com/wp-content/uploads/2022/06/AttachedFilePDF-2048x878.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<h3 class="wp-block-heading">Callout Annotations</h3>



<p>These kind of annotations are perfect for pointing our or calling attention to any other item in the PDF page. They are highly customizable- you can decide for example a solid or dashed line, the termination of the line, the color and, of course the text to be displayed in the annotation itself.</p>



<p>This is an example showing how to add a Callout annotation to a PDFDocument:</p>



<pre class="wp-block-code"><code>Var d As New PDFDocument
Var g As Graphics = d.Graphics
Const kContentText As String = "Callout Annotation in PDF"

g.FontSize = 40
g.Bold = True
g.DrawText(kContentText, 40, 60)

g.Bold = False
g.FontSize = 12
g.DrawText(kSampleText, 40, 100, 200)

Var originY As Double = (g.TextHeight(kSampleText, 200) / 2)

Var tCallout As New PDFCallout("Callout Example", New Point(250, originY), New Point(300, originY + 50), _
 New Point(350, originY + 50), 100, 50)

tCallout.BorderStyle = PDFAnnotation.BorderStyles.Dashed
tCallout.DashPattern = Array(2.0, 2.0)
tCallout.DrawingColor = Color.Orange
tCallout.LineEndingStyle = PDFAnnotation.LineEndingStyles.OpenArrow
tCallout.Text = "Some sample text in the annotation"
tCallout.FontSize = 9.5

d.AddCallout(tCallout)

// Saving the created PDF document to the selected path.
Var f As FolderItem = FolderItem.ShowSaveFileDialog("","PDFCalloutExample.pdf")

If f &lt;&gt; Nil Then
  
  d.Save(f)
  
End If
</code></pre>



<p>Where <code>kSampleText</code> is a Constant added to the project containing some sample text to be put in the page of the PDF.</p>



<p>And this is how the Callout will look like when opening the resulting PDF file in the viewer app:</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="599" src="https://blog.xojo.com/wp-content/uploads/2022/06/Callout-1024x599.png" alt="" class="wp-image-10491" srcset="https://blog.xojo.com/wp-content/uploads/2022/06/Callout-1024x599.png 1024w, https://blog.xojo.com/wp-content/uploads/2022/06/Callout-300x176.png 300w, https://blog.xojo.com/wp-content/uploads/2022/06/Callout-768x450.png 768w, https://blog.xojo.com/wp-content/uploads/2022/06/Callout-1536x899.png 1536w, https://blog.xojo.com/wp-content/uploads/2022/06/Callout-2048x1199.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<h3 class="wp-block-heading">Line Annotations</h3>



<p>A &#8220;Line&#8221; annotation displays a straight line on the page with a text caption inside the line or above it.</p>



<p>It is also possible to add leader lines to both sides of the main line (with possitive or negative values) plus set other properties as the type of the line (solid, dashed, etc), the kind of termination used on both ends of the main line (i.e: open/close arrow, butt, circle, diamond, square…), the drawing color, line width or font size.</p>



<p>This is how a Line annotation looks like when the resulting PDFDocument is viewed using Acrobat Reader (in this case, using Leader lines):</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="605" src="https://blog.xojo.com/wp-content/uploads/2022/06/Line-1024x605.png" alt="" class="wp-image-10493" srcset="https://blog.xojo.com/wp-content/uploads/2022/06/Line-1024x605.png 1024w, https://blog.xojo.com/wp-content/uploads/2022/06/Line-300x177.png 300w, https://blog.xojo.com/wp-content/uploads/2022/06/Line-768x454.png 768w, https://blog.xojo.com/wp-content/uploads/2022/06/Line-1536x907.png 1536w, https://blog.xojo.com/wp-content/uploads/2022/06/Line-2048x1210.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<h3 class="wp-block-heading">Video Annotations</h3>



<p>Yes, you can embed .mp4 files in the PDF created with PDFDocument, and these will be played from the PDF itself. This will increase the size of the generated PDF file because it will add the size of the embedded mp4 file itself! So it is good practice to optimize the video files as much as possible and use the video resolution you want them to be played and not a higher one.</p>



<p>You can also add this kind of content as an Attached File annotation too. In both cases the data of the file will be embedded in the generated PDF file. The main difference in this case is that the mp4 file will be opened using an external app and that you&#8217;ll be able to include other video file format besides .mp4.</p>



<p>The way to add this kind of annotation to a PDFDocument instance is quite simple, for example:</p>



<pre class="wp-block-code"><code>Var d As New PDFDocument
Var g As Graphics = d.Graphics
Const kContentText As String = "Embedded Video Annotation"

g.FontSize = 30
g.DrawText(kContentText, 40, 60)

If exampleVideo &lt;&gt; Nil Then
  
  // Creating a new EmbeddedSound.
  d.AddEmbeddedMovie(exampleVideo, 40, 100, 478, 360)
  
  // Saving the created PDF document to the selected path.
  Var f As FolderItem = FolderItem.ShowSaveFileDialog("","PDFEmbeddedVideo.pdf")
  
  If f &lt;&gt; Nil Then
    
    d.Save(f)
    
  End If
End If
</code></pre>



<p>Where <code>exampleVideo</code> is a FolderItem Property that has been added to the project. This is how a video annotation will look like when opening the resulting PDF in Acrobat Reader:</p>



<figure class="wp-block-image is-style-default"><img loading="lazy" decoding="async" width="918" height="600" src="https://blog.xojo.com/wp-content/uploads/2022/06/VideoAnnotation.gif" alt="" class="wp-image-10494"/></figure>



<h3 class="wp-block-heading">Sound Annotations</h3>



<p>In addition to video annotations, it is also possible to add sound files that can be played from the PDF itself. In this case, the audio files need to be in AIFF format with 2 audio channels (stereo), 16 bits of resolution and a sampling frequency of 44,1 kHz.</p>



<p>As it is the case with video annotations, you can opt to add this kind of content as an Attached File annotation, so it will be opened with an external app and opens the range of sound file formats you can embed into the PDF.</p>



<p>The way to add Sound annotations using PDFDocument is shown here:</p>



<pre class="wp-block-code"><code>Var d As New PDFDocument
Var g As Graphics = d.Graphics
g.FontSize = 30

Const kContentText As String = "Embedded Sound Annotation"

Var x, y, width, height As Double

x = g.Width/2 - width/2
y = 60

width = g.TextWidth(kContentText)
height = g.TextHeight

g.DrawText(kContentText, x, y)

If exampleSound &lt;&gt; Nil Then
  
  // Creating a new EmbeddedSound.
  d.AddEmbeddedSound(exampleSound,x,y,width,height)
  
  // Saving the created PDF document to the selected path.
  Var f As FolderItem = FolderItem.ShowSaveFileDialog("","PDFEmbeddedSound.pdf")
  
  If f &lt;&gt; Nil Then
    
    d.Save(f)
    
  End If
End If
</code></pre>



<p>Here <code>exampleSound</code> is a FolderItem Property added to the project. And this is how a Sound annotation will look when the PDF document is opened using Acrobat Reader:</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="361" src="https://blog.xojo.com/wp-content/uploads/2022/06/SoundAnnotation-1024x361.png" alt="" class="wp-image-10495" srcset="https://blog.xojo.com/wp-content/uploads/2022/06/SoundAnnotation-1024x361.png 1024w, https://blog.xojo.com/wp-content/uploads/2022/06/SoundAnnotation-300x106.png 300w, https://blog.xojo.com/wp-content/uploads/2022/06/SoundAnnotation-768x271.png 768w, https://blog.xojo.com/wp-content/uploads/2022/06/SoundAnnotation-1536x542.png 1536w, https://blog.xojo.com/wp-content/uploads/2022/06/SoundAnnotation-2048x722.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<h3 class="wp-block-heading">Markup Annotations</h3>



<p>A Markup annotation is intended to mark an underlying text content using any of the different available types, for example &#8220;Highlight&#8221;, &#8220;Squiggly&#8221; (usually used to mark a text that needs some kind of correction), &#8220;Underline&#8221; or &#8220;Strikeout&#8221;. Besides the Markup type, it is also possible to set the color of the annotation.</p>



<p>For example, the following snippet of code adds two Markup annotations to the page of the PDFDocument using the Highlight and Squiggly types:</p>



<pre class="wp-block-code"><code>Var d As New PDFDocument
Var g As Graphics = d.Graphics
Const kContentText As String = "Markup Annotation in PDF"

g.FontSize = 40
g.Bold = True
g.DrawText(kContentText, 40, 60)

// Adding a Markup annotation with the Highlight type (Default)
d.AddMarkup(40,40,g.TextWidth(kContentText),g.FontSize,"Let's focus on this Section")

g.Bold = False
g.FontSize = 12
g.DrawText(kSampleText, 40, 100, g.Width-80)

// Adding a Markup annotation with the Squiggly type
d.AddMarkup(40,195,210,g.FontSize,"Some text to correct!",Color.Red,PDFAnnotation.MarkupTypes.Squiggly)

// Saving the created PDF document to the selected path.
Var f As FolderItem = FolderItem.ShowSaveFileDialog("","PDFMarkupExample.pdf")

If f &lt;&gt; Nil Then
  
  d.Save(f)
  
End If</code></pre>



<p>And this is how it looks when the resulting document is opened in Adobe Acrobat Reader:</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="632" src="https://blog.xojo.com/wp-content/uploads/2022/06/MarkupAnnotation-1024x632.png" alt="" class="wp-image-10499" srcset="https://blog.xojo.com/wp-content/uploads/2022/06/MarkupAnnotation-1024x632.png 1024w, https://blog.xojo.com/wp-content/uploads/2022/06/MarkupAnnotation-300x185.png 300w, https://blog.xojo.com/wp-content/uploads/2022/06/MarkupAnnotation-768x474.png 768w, https://blog.xojo.com/wp-content/uploads/2022/06/MarkupAnnotation-1536x949.png 1536w, https://blog.xojo.com/wp-content/uploads/2022/06/MarkupAnnotation-2048x1265.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<h3 class="wp-block-heading">Bonus</h3>



<p>Let me end with one other minor improvement to PDFDocument annotations: starting with Xojo 2022r2 all of them include metadata information about the creation and modification date and time. this information will be displayed as part of the annotation metadata when the item is selected in the viewer app.</p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>PDFDocument: How to Add New Content to a Given Page</title>
		<link>https://blog.xojo.com/2022/06/02/pdfdocument-how-to-add-new-content-to-a-given-page/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Thu, 02 Jun 2022 13:00:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Multi-Platform Development]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[Rapid Application Development]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Xojo API 2.0]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=10413</guid>

					<description><![CDATA[When we create a PDF document is impossible (in most of the cases) to anticipate how many pages it will have. And yet, that is something that we are going to need if, for example, we want to add a footer reflecting the current page number over the total of pages in the document. The solution is using the PageCount and CurrentPage properties in the PDFDocument class. ]]></description>
										<content:encoded><![CDATA[
<p>When creating a PDF it is not always possible to anticipate how many pages the document will have. And yet, that is necessary, for example, to add a footer reflecting the current page number over the total of pages in the document. So how do you add this new content to your PDFs?</p>



<p>The solution is to use the <a href="https://documentation.xojo.com/api/pdf/pdfdocument.html#pdfdocument-pagecount"><code>PageCount</code></a> and <a href="https://documentation.xojo.com/api/pdf/pdfdocument.html#pdfdocument-currentpage"><code>CurrentPage</code></a> properties in Xojo&#8217;s <a href="https://documentation.xojo.com/api/pdf/pdfdocument.html#pdfdocument"><code>PDFDocument</code></a> class. The PageCount property gives the total number of pages in the PDF, and the the CurrentPage property (read/write) can be used to reach a given page within a PDF being created. This way, when we assign a new value to the CurrentPage property, it will retrieve the current <a href="https://documentation.xojo.com/api/graphics/graphics.html#graphics">Graphics</a> context for that page in order to continue adding new content.</p>



<p>Let&#8217;s see how this works through this example. Let&#8217;s create a 10 page PDF and then add the numbered footer on every page of the document:</p>



<pre class="wp-block-preformatted">Var d As New PDFDocument
Var g As Graphics = d.Graphics

// Adding a total of 10 pages to the PDF
For n As Integer = 1 To 9
  g.DrawText("Some sample text in page #" + n.ToString, 20, 20)
  g.NextPage
Next n

// Once we create the pages with some content on them,
// we iterate on every page in order to add the footer.
// Remember that the first page in a PDF document starts at 1!
Var x As Integer = d.PageCount
For i As Integer = 1 To x

// Here is where we set which will be the current "active" page;
// that is, the one retrieving the current Graphics context.
d.CurrentPage = i
g.DrawText("Page " + i.ToString + " of " + x.ToString, 20, g.Height - 30)
Next i

// Lastly, we save our PDF to a FolderItem.
d.Save(SpecialFolder.Desktop.Child("CurrentPage.PDF"))</pre>



<p>Run this sample snippet of code and you&#8217;ll get a PDF on your computer Desktop. Open it using your preferred PDF viewer app and you&#8217;ll see how the second loop was able to draw again on every one of the pages from the PDF we created.</p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How To Download and Preview PDFs in Xojo Web Apps</title>
		<link>https://blog.xojo.com/2022/05/31/how-to-download-and-preview-pdfs-in-xojo-web-apps/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Tue, 31 May 2022 18:10:19 +0000</pubDate>
				<category><![CDATA[Tips]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Web 2.0]]></category>
		<category><![CDATA[webdev]]></category>
		<category><![CDATA[Xojo API 2.0]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=10417</guid>

					<description><![CDATA[Web Apps
How to download and preview PDFs in Xojo Web apps may be one of the most asked questions involving PDFDocument (font handling is a close second) I get. If you are interested in finding the best, and simplest, way to do this, continue reading.]]></description>
										<content:encoded><![CDATA[
<p>How to download and preview PDFs in Xojo Web apps may be one of the most asked questions involving <a href="https://documentation.xojo.com/api/pdf/pdfdocument.html#pdfdocument">PDFDocument</a> (<a href="https://blog.xojo.com/2022/04/05/pdfdocument-font-handling-improvements/">font handling</a> is a close second) I get. If you are interested in finding the best, and simplest, way to do this, continue reading.</p>



<span id="more-10417"></span>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="917" src="https://blog.xojo.com/wp-content/uploads/2022/05/Captura-de-Pantalla-2022-05-18-a-las-12.53.12-1024x917.png" alt="" class="wp-image-10418" srcset="https://blog.xojo.com/wp-content/uploads/2022/05/Captura-de-Pantalla-2022-05-18-a-las-12.53.12-1024x917.png 1024w, https://blog.xojo.com/wp-content/uploads/2022/05/Captura-de-Pantalla-2022-05-18-a-las-12.53.12-300x269.png 300w, https://blog.xojo.com/wp-content/uploads/2022/05/Captura-de-Pantalla-2022-05-18-a-las-12.53.12-768x688.png 768w, https://blog.xojo.com/wp-content/uploads/2022/05/Captura-de-Pantalla-2022-05-18-a-las-12.53.12-1536x1375.png 1536w, https://blog.xojo.com/wp-content/uploads/2022/05/Captura-de-Pantalla-2022-05-18-a-las-12.53.12-2048x1833.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p>To start, create a Web project, select <a href="https://documentation.xojo.com/api/user_interface/web/webpage.html#webpage">WebPage1</a> in the Navigator and drop a <a href="https://documentation.xojo.com/api/user_interface/web/webbutton.html#webbutton">WebButton</a> from the Library onto the upper-center of the page in the Layout Editor. In the associated Inspector Panel for the button change the following property:</p>



<ul class="wp-block-list"><li><strong>Caption:</strong> Create PDF</li></ul>



<p>Next, add the <code>Pressed</code> Event Handler to it and type the following snippet of code in the associated Code Editor:</p>



<pre class="wp-block-preformatted">// Nothing really interesting here
// Create a new PDFDocument instance
// and assign its Graphic context to
// a variable
Var d As New PDFDocument
Var g As Graphics = d.Graphics

// The content of the PDF
// not that much, but it works for the
// main topic we are interested in
g.DrawText("Really simple PDF content", 20, 20)

// Here is where the **important** thing starts
// Creating a new WebFile instance and assigning it
// to the wf property added to the WebPage1 page
wf = New WebFile

// This is the thing: the PDFDocument.ToData method
// returns as a MemoryBlock (Direct conversion to String)
// the inner contents of the PDF document at this point
// so assign that to the "data" property of the
// WebFile instance
wf.Data = d.ToData

// It's important to set the right MIMEType for the file
// in this case, it's a PDF file
wf.MIMEType = "application/pdf"

// We assign the file name…
wf.Filename = "SamplePDF.pdf"

// …and set the ForceDownload to true…
wf.ForceDownload = True

// …so the file is, in effect, downloaded when calling
// the Download method on our WebFile instance
Call wf.Download

// Because we want to display the PDF file in an HTMLViewer
// set the ForceDownload property back to False
wf.ForceDownload = False

// And, finally, preview the PDF Document loading it in the
// HTMLviewer added to the WebPage1 page
HTMLViewer1.LoadURL(wf.URL)
</pre>



<p>As you can see here, this simple fragment of code is in charge of creating a sample PDF document, downloading it and also previewing it in an <a href="https://documentation.xojo.com/api/user_interface/web/webhtmlviewer.html#webhtmlviewer">HTMLViewer</a> instance. Now, add an HTMLViewer control to the WebPage1 page.</p>



<p>Select the WebPage1 item in the Navigator again so it is visible in the Layout Editor. Next, drag the HTMLViewer control from the Library and drop it below the WebButton added in the previous step.</p>



<p>With the HTMLViewer1 control selected in the Layout Editor, click on the four lock icons under the Locking section from the associated Inspector Panel so they are closed.</p>



<p>Finally, add the expected <a href="https://documentation.xojo.com/api/web/webfile.html#webfile">WebFile</a> property to the WebPage1 page using the following values in the associated Inspector Panel:</p>



<ul class="wp-block-list"><li><strong>Name:</strong> wf</li><li><strong>Data Type:</strong> WebFile</li><li><strong>Scope:</strong> Private</li></ul>



<p>You&#8217;ll probably want to move this property to the <a href="https://documentation.xojo.com/api/web/websession.html#websession">Session</a> object in your Web projects so every connected user to the app can handle their own generated PDF documents.</p>



<p>And…&nbsp;that&#8217;s all! Run the project, click the button and see how it works.</p>



<p>Have fun!</p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Creating Presentations with PDF and Xojo</title>
		<link>https://blog.xojo.com/2022/05/26/creating-presentations-with-pdf-and-xojo/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Thu, 26 May 2022 15:35:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Desktop]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[XDC]]></category>
		<category><![CDATA[Xojo Cloud]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=10319</guid>

					<description><![CDATA[I know, I know, it's not the usual thing to do when making presentations, but did you know that it is possible to create presentations using Xojo's and PDF? If you're interested in this little experiment, read on and I'll show you how to do it using Xojo's PDFDocument. ]]></description>
										<content:encoded><![CDATA[
<p>I know, I know, it&#8217;s not the <em>usual</em> thing to do when making presentations, but did you know that it is possible to create presentations using Xojo&#8217;s and PDF? If you&#8217;re interested in this little experiment, read on and I&#8217;ll show you how to do it using Xojo&#8217;s <a href="https://documentation.xojo.com/api/pdf/pdfdocument.html#pdfdocument">PDFDocument</a>. </p>



<span id="more-10319"></span>



<p>Why, you ask? What are the advantages of using a PDF for your presentations? PDF is portable, meaning you can distribute these files easily, usually, with a small file footprint. The content is vectorial (except for images), what means that it will look great no matter the screen resolution of the display/projector used for playing the presentation.</p>



<p>There is one current issue to watch out for, currently <a href="https://acrobat.uservoice.com/forums/590923-acrobat-for-windows-and-mac/suggestions/44616444-fullscreen-page-transitions-in-pdfs-no-longer-work">there&#8217;s a bug on macOS</a> where Acrobat Reader is not able to apply the assigned transitions on Big Sur and later; they still work under Catalina and previous versions of macOS.</p>



<p>In this example project I will create a shortened version of the slides I used in the <a href="https://youtu.be/aSfff3hQaX4">Using Xojo&#8217;s PDFDocument</a> presentation. You&#8217;ll need to change the font names (and any other item) to those you are using and that are installed in your computer.</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="960" height="540" src="https://blog.xojo.com/wp-content/uploads/2022/04/Presentation.gif" alt="" class="wp-image-10320"/></figure>
</div>


<h3 class="wp-block-heading">Setting the Viewer Options</h3>



<p>Start by creating a new project for the target you&#8217;re most comfortable with &#8211; Xojo&#8217;s PDFDocument is cross-platform and supported on Desktop, Web, iOS and Console projects. Next, add the Opening Event Handler to the default DesktopWindow/WebWindow/MobileScreen, or choose the Run Event Handler if you chose to create a new Console Project.</p>



<p>Write the following lines of code in the associated Code Editor:</p>



<pre class="wp-block-preformatted">// Let's create a new PDFDocument instance with
// the page size set to HD resolution

Var Presentation As New PDFDocument(1920, 1080)

// Let's make sure that the fonts used are embedded in the
// document, so there are no unexpected problems when the
// PDF is opened in a device that doesn't have that
// same fonts installed

Presentation.EmbeddedFonts = True</pre>



<p>The next lines of code will set the default for the View mode of the document when it is opened in Acrobat Reader or any other PDF reader. Since it&#8217;s a presentation, you&#8217;ll likely want the document to be opened in Full Screen mode by default, so let&#8217;s make that happen:</p>



<pre class="wp-block-preformatted">// Let's create a new Instance from the PDFViewerOptions class

Var ViewerOptions As New PDFViewerOptions

// And set the FullScreen property to True
// so the document will set that view size
// when opened in the PDF Viewer app

ViewerOptions.FullScreen = True</pre>



<h3 class="wp-block-heading">Drawing the Background of the Page</h3>



<p>Use a linear gradient brush to fill in the background of all the slides. For convenience, create a new method for it using the following values in the Inspector Panel:</p>



<ul class="wp-block-list"><li><strong>Name:</strong> DrawPageBackground</li><li><strong>Parameters:</strong> g As Graphics</li></ul>



<p>Type the following code in the associated Code Editor for the method:</p>



<pre class="wp-block-preformatted">Static backgroundfilling As LinearGradientBrush

If backgroundfilling = Nil Then
  backgroundfilling = New LinearGradientBrush
  backgroundfilling.StartPoint = New Point(g.Width / 2, 0)
  backgroundfilling.EndPoint = New Point(g.Width / 2, g.Height)
  backgroundfilling.GradientStops.Add(New Pair(0.0, &amp;c000000))
  backgroundfilling.GradientStops.Add(New Pair(0.7, &amp;c000000))
  backgroundfilling.GradientStops.Add(New Pair(1.0, &amp;ccccccc))
End If

g.Brush = backgroundfilling
g.FillRectangle(0, 0, g.Width, g.Height)</pre>



<p>All this code does is create a LinearGradientBrush instance ranging from full black to some degree of gray at the bottom of the page. Because we are not going to change the values of the gradient every time we need to call the method, it makes sense to assign it to a Static instead of a Variable.</p>



<p>Then the LinearGradientBrush is assigned to the Brush property of the received Graphic context and, finally, used as the &#8220;filling color&#8221; when drawing the filled rectangle.</p>



<h3 class="wp-block-heading">Drawing the Header</h3>



<p>Now add the method that will be responsible for drawing the header shared by all the slides. Use the following values in the Inspector Panel:</p>



<ul class="wp-block-list"><li><strong>Method Name:</strong> DrawTopHeader</li><li><strong>Parameters:</strong> g As Graphics</li></ul>



<p>And type the following code in the associated Code Editor:</p>



<pre class="wp-block-preformatted">Const kPDFDocumentHeader As String = "PDFDocument"

DrawUpperBand(g, 0, 50)

g.FontName = "Helvetica"
g.FontSize = 180
g.Bold = True

Var x As Double = g.Width / 2 - g.TextWidth(kPDFDocumentHeader) / 2
Var y As Double = 220

g.DrawingColor = &amp;cC9F2C900
g.DrawText(kPDFDocumentHeader, x + 4, 224)

g.DrawingColor = Color.Black

Static linearGradient As LinearGradientBrush

If linearGradient = Nil Then
  Lineargradient = New LinearGradientBrush
  linearGradient.StartPoint = New point(x, y - 224)
  linearGradient.EndPoint = New point(x, y)
  linearGradient.GradientStops.Add(New Pair(0.0, &amp;c00BD4E00))
  linearGradient.GradientStops.Add(New Pair(0.7, &amp;c00FD1F00))
  linearGradient.GradientStops.Add(New Pair(1.0, &amp;c25712900))
End If

g.Brush = LinearGradient
g.DrawText(kPDFDocumentHeader, x, y)</pre>



<p>As you can see, this is quite similar to the previous code. We are using a new Linear Gradient as the filling for the &#8220;PDFDocument&#8221; text. But first, it calls the DrawUpperBand method. This is a method that will draw a picture with a 50% opacity behind the header text, as well as the XDC logo in the lower left corner of the slide. Add a new method using the following values:</p>



<ul class="wp-block-list"><li><strong>Method Name:</strong> DrawUpperBand</li><li><strong>Parameters:</strong> g As Graphics, x As Integer, y As Integer</li></ul>



<p>Type the following snippet of code in the associated Code Editor:</p>



<pre class="wp-block-preformatted">g.Transparency = 50.0
g.DrawPicture(UpperBand, x, y)
g.Transparency = 0
g.DrawPicture(XDC2x, 20, g.Height - XDC2x.Height)</pre>



<p>Both &#8220;UpperBand&#8221; and &#8220;XDC2x&#8221; are PNG image files added to the project.</p>



<h3 class="wp-block-heading">NextPage</h3>



<p>Because the background and the header are common items in all the slides, we will render them every time we add a new slide (page) to the presentation (document). Create a new method using the following values:</p>



<ul class="wp-block-list"><li><strong>Method Name:</strong> NextPage</li><li><strong>Parameters:</strong> g As Graphics</li></ul>



<p>And type the following lines of code:</p>



<pre class="wp-block-preformatted">g.NextPage(1920, 1080)
DrawPageBackground(g)
DrawTopHeader(g)</pre>



<h3 class="wp-block-heading">Creating the Content of the Slides</h3>



<p>Now let&#8217;s add the method that will be responsible for adding the text of the main topic on every slide:</p>



<ul class="wp-block-list"><li><strong>Method Name:</strong> DrawTopic</li><li><strong>Parameters:</strong> g As Graphics, topic As String</li></ul>



<p>And type the following code in the associated Code Editor:</p>



<pre class="wp-block-preformatted">Var x, y As Double
g.FontName = "Anoxic Light"
g.FontSize = 150

x = g.Width / 2 - g.TextWidth(topic) / 2
y = g.Height / 2 - g.TextHeight / 2

Static LinearGradient As LinearGradientBrush

If LinearGradient = Nil Then
  linearGradient = New LinearGradientBrush
  linearGradient.StartPoint = New Point(x, y)
  linearGradient.EndPoint = New Point(x, y - 80)
  linearGradient.GradientStops.Add(New pair(1.0, &amp;c9FE1FF00))
  linearGradient.GradientStops.Add(New pair(0.0, &amp;cF6F6F600))
End If

g.Brush = linearGradient
g.DrawText(topic, x, y)</pre>



<h3 class="wp-block-heading">Setting Transitions Between Slides</h3>



<p>PDFDocument does support the range of transitions available under the PDF standard. In this case we are going to use the simplest: Fade. So, create a new method with the following values:</p>



<ul class="wp-block-list"><li><strong>Method Name:</strong> AddTransitions</li><li><strong>Parameters:</strong> d as PDFDocument</li></ul>



<p>And type the following lines of code in the associated Code Editor:</p>



<pre class="wp-block-preformatted">// New PDFTransition instance, using the Fade style
// with one second of length.

Var t As New PDFTransition(PDFTransition.Styles.Fade, 1)

// And apply it on every page of the PDFDocument, starting on Page 2.
If d.PageCount &gt; 2 Then
  For n As Integer = 2 To d.PageCount
    d.TransitionAt(n) = t
  Next
End If</pre>



<h3 class="wp-block-heading">Putting It All Together</h3>



<p>Now we have all the pieces needed to create this small presentation in PDF. Go back to the Opening Event Handler and type the following lines of code below the last one:</p>



<pre class="wp-block-preformatted">DrawPageBackground(g)
DrawTopHeader(g)
DrawTopic(g, "First Slide")
NextPage(g)
DrawTopic(g, "Second Slide")
NextPage(g)
DrawTopic(g, "Third Slide")
NextPage(g)
DrawTopic(g, "Fourth Slide")

AddTransitions(d)

d.Save(SpecialFolder.Desktop.Child("Presentation.pdf"))</pre>



<p>Done! Run the project and the PDF document will be saved to your computer Desktop. Once you open it in Adobe Reader, the app will detect that the document wants to use the full screen mode and, as soon as you confirm, it will begin the presentation. Depending on your preferences in Acrobat Reader, you may need to use the mouse button or arrow keys to change slides, or it may automatically advance to the next slide after the amount of time set.</p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Graphics: Right and Center Aligned Text</title>
		<link>https://blog.xojo.com/2022/05/17/graphics-right-and-center-aligned-text/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Tue, 17 May 2022 13:00:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Desktop]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Graphics]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Xojo API 2.0]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=10351</guid>

					<description><![CDATA[The DrawText method from the Graphics class offers a simple way to left-align text at the given X and Y coordinates, even applying a wrap value to wrap every line of the text block at the provided width value. Wouldn't it be great to be able to do the same thing while aligning blocks of text to the right and center? Continue reading and I will show you a technique you can use as the starting point which you can fine-tune to your specific needs.]]></description>
										<content:encoded><![CDATA[
<p>The <a href="https://documentation.xojo.com/api/graphics/graphics.html#graphics-drawtext">DrawText</a> method from the <a href="https://documentation.xojo.com/api/graphics/graphics.html#graphics">Graphics</a> class offers a simple way to left-align text at the given X and Y coordinates, even applying a wrap value to wrap every line of the text block at the provided width value. Wouldn&#8217;t it be great to be able to do the same thing while aligning blocks of text to the right and center? Continue reading and I will show you a technique you can use as the starting point which you can fine-tune to your specific needs.</p>



<div class="wp-block-image wp-image-10353 size-large is-style-default"><figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="665" src="https://blog.xojo.com/wp-content/uploads/2022/05/AlignmentLinux-1024x665.png" alt="" class="wp-image-10353" srcset="https://blog.xojo.com/wp-content/uploads/2022/05/AlignmentLinux-1024x665.png 1024w, https://blog.xojo.com/wp-content/uploads/2022/05/AlignmentLinux-300x195.png 300w, https://blog.xojo.com/wp-content/uploads/2022/05/AlignmentLinux-768x499.png 768w, https://blog.xojo.com/wp-content/uploads/2022/05/AlignmentLinux.png 1472w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption>Right-aligned and centered text on Linux Desktop, both in a Picture and a document created with PDFDocument.</figcaption></figure></div>



<h3 class="wp-block-heading">Graphics Extensions</h3>



<p>To start, and because we want to provide this ability to any graphic context, it makes sense to include all our logic in a Module. Let&#8217;s name it GraphicExtensions (as usual you can opt to use any other name). Start a new Xojo project and add a new Module to it using the following values in the Inspector Panel:</p>



<ul class="wp-block-list"><li><strong>Name:</strong> GraphicsExtensions</li></ul>



<p>Next, and with the GraphicsExtensions item selected in the Navigator, add a new method to it using the following values in the associated Inspector Panel:</p>



<ul class="wp-block-list"><li><strong>Method Name:</strong> DrawText</li><li><strong>Parameters:</strong> Extends g As Graphics, value As String, x As Double, y As Double, wrap As Double, alignment As TextAlignments = TextAlignments.Left</li><li><strong>Scope:</strong> Global</li></ul>



<p>As you can see, it nearly replicates the standard DrawText method from the Graphics class. Some things to note here, we are using the <a href="https://documentation.xojo.com/api/language/extends.html#extends">Extends</a> keyword in combination with the first parameter to instruct the compiler that this method will &#8220;extend&#8221; the existing functionality of the Graphics class, so you&#8217;ll be able to invoke it using the usual dot notation on any instance created from the Graphics class.</p>



<p>The second thing is the last of the parameters &#8220;alignment As TextAlignments&#8221; <a href="https://documentation.xojo.com/api/text/textalignments.html#textalignments">TextAlignments</a> is a global enumeration that we are going to use to learn the text alignment the user wants to apply to the block of text.</p>



<p>Next, type the following snippet of code in the associated Code Editor for the method:</p>



<pre class="wp-block-preformatted">#Pragma DisableBackgroundTasks
#Pragma DisableBoundsChecking
#Pragma NilObjectChecking False

value = value.ReplaceLineEndings(EndOfLine)

Select Case Alignment
  
Case TextAlignments.Default, TextAlignments.Left
  
  g.DrawText(value, x, y + g.TextHeight, wrap - x)
  
Case TextAlignments.Center, TextAlignments.Right
  
  Var tOutput() As String = PrepareOutput(g, value, wrap, x)
  
  Var tx, ty As Double
  ty = y + g.TextHeight
  
  Select Case Alignment
    
  Case TextAlignments.Center
    
    For Each s As String In tOutput
      
      tx = If(Wrap = 0, ((g.Width - Wrap) / 2 - g.TextWidth(s) / 2) + (x / 2), (wrap / 2 - g.TextWidth(s) / 2) + (x / 2))
      g.DrawText(s, tx, ty)
      ty = ty + g.TextHeight
      
      If ty &gt; g.Height Then Exit
      
    Next
    
  Case TextAlignments.Right
    
    For Each s As String In tOutput
      
      tx = If(Wrap = 0, (g.Width - g.TextWidth(s)) + x / 2, (wrap - x) - g.TextWidth(s) + x)
      g.DrawText(s, tx, ty)
      ty = ty + g.TextHeight
      
      If ty &gt; g.Height Then Exit
      
    Next
    
  End Select
  
End Select
</pre>



<p>As you can see, this code looks into the value of the Alignment parameter to see the approach to apply. If the Alignment equals to Default or Left we simply call the standard DrawText method on the received graphics context represented by the &#8220;g&#8221; variable. If not, we need to do some stuff to the received block of text to create the required chunks (or lines) that do fit the available width plus the received wrapping value. This is done in the PrepareOutput method.</p>



<p>Once we have all the lines with the apropiate widths in the Output array, then we only need to do some basic maths in order to calculate the final TX coordinate for every line, incrementing the TY coordinate on every new line to draw. As you can see, and in order to speed-up things a bit more, we check if the calculated TY coordinate is beyond the visible area of the graphic context and, if it is the case, we exit the function (it wouldn&#8217;t make much sense drawing text that is not going to be visible and whose processing consumes time).</p>



<p>Of course, the calculation of the TX and TY coordinates depends on the value of the Alignment parameter; that is, if the block of text is going to be drawn right aligned or centered.</p>



<h3 class="wp-block-heading">Calculating Every Line Width</h3>



<p>Now add the PreapareOutput method to the GraphicsExtensions module using the following values in the associated Inspector Panel:</p>



<ul class="wp-block-list"><li><strong>Method Name:</strong> PrepareOutput</li><li><strong>Parameters:</strong> g As Graphics, value As string, wrap As Double, x As Double</li><li><strong>Return Type:</strong> String()</li><li><strong>Scope:</strong> Private</li></ul>



<p>And typing the following snippet of code in the associated Code Editor:</p>



<pre class="wp-block-preformatted">#Pragma DisableBoundsChecking
#Pragma DisableBackgroundTasks
#Pragma NilObjectChecking False

Var totalWidth As Double = If(wrap = 0, g.Width - x, wrap - x)

Var Input() As String = value.ToArray(EndOfLine)
Var output() As String

For Each s As String In Input
  
  If g.TextWidth(s) &lt;= totalWidth Then
    output.Add(s)
  Else
    AdjustWidth(g, s, totalWidth, output)
  End If
  
Next

Return output
</pre>



<p>Once again, the first lines are some pragmas put in place to speed-up things, then the totalWidth variable will store the required maximum width value for every line. The Input array is going to store every paragraph from the source text, while the Output array will store every processed line and, the one returned to the method calling PrepareOutput.</p>



<p>Then we need to iterate every entry in the Input array and check if its width meets the totalWidth requirement. If it does, then that entry will be added to the Output array; if not, we still need to split the &#8220;paragraph&#8221; into as many chunks of text as needed that meet the expected maximum width. That is something that&#8217;s going to be done by the AdjustWidth method.</p>



<h3 class="wp-block-heading">Splitting Chunks of Text …&nbsp;Recursively</h3>



<p>Add the third, and last required, method to the GraphicExtensions module using the following values in the associated Inspector Panel:</p>



<ul class="wp-block-list"><li><strong>Method Name:</strong> AdjustWidth</li><li><strong>Parameters:</strong> g As Graphics, s As String, width As Double, ByRef output() As String</li><li><strong>Scope:</strong> Private</li></ul>



<p>Next, type the following lines of code in the associated Code Editor:</p>



<pre class="wp-block-preformatted">#Pragma DisableBoundsChecking
#Pragma DisableBackgroundTasks
#Pragma NilObjectChecking False

Var n As Integer

If g.TextWidth(s) &lt;= width Then
  output.Add(s)
Else
  
  // This can be improved pre-calculating the initial value for "n"…&nbsp;so it's
  // left as an exercise for the reader :-)
  
  While round(g.TextWidth(s.Left(s.Length - n))) &gt; width
    n = n + 1
  Wend
  
  output.Add(s.Left(s.Length - n))
  
  AdjustWidth(g, s.Right(n), width, output)
  
End If
</pre>



<p>As you can see, if the width of the received string is less than or equal to the expected width, then it is added to the Output array. If not, we are using a really less than optimal technique to calculate the appropriate one, saving the resulting string to the Output array and passing the remaining of the string again to the method. You&#8217;ll probably want to change some things here to better pre-calculate the initial value of the <code>n</code> variable.</p>



<h3 class="wp-block-heading">Testing It</h3>



<p>We have everything in place, so let&#8217;s test it! Start by adding a new constant to the Window1 window and name it <code>kSampleText</code>. Use the associated Inspector Panel to assign the block of text you want to use for testing (personally I like to use the <a href="https://www.lipsum.com">https://www.lipsum.com</a> website for getting sample text).</p>



<p>If you prefer, you can <a href="https://www.dropbox.com/s/amt86u9fnbq31xh/GraphicsExtensions.xojo_binary_project.zip?dl=1">download the complete Example project from this link</a>.</p>



<p>Add next the Opening Event Handler to the Window1 window and type following snippet of code in the associated Code Editor:</p>



<pre class="wp-block-preformatted">Var p As New Picture(612, 792)
Var d As New PDFDocument

Var g As Graphics = p.Graphics
g.FontName = "Helvetica"
Var gPDF As Graphics = d.Graphics

g.DrawText(kSampleText, 40, 10, 570, TextAlignments.Right)
gPDF.DrawText(kSampleText, 40, 10, 570, TextAlignments.Right)

Var tH As Double = g.TextHeight(kSampleText, 570) + g.TextHeight * 4
Var tPH As Double = gPDF.TextHeight(kSampleText, 570) + gPDF.TextHeight * 4

g.DrawText(kSampleText, 40, th, 570, TextAlignments.Center)
gPDF.DrawText(kSampleText, 40, tPh, 570, TextAlignments.Center)

CustomDesktopCanvas1.Image = p
d.Save(SpecialFolder.Desktop.Child("PDFTextAlignment.pdf"))
</pre>



<p>As you can see, I chose the &#8220;Helvetica&#8221; font, but you can change it to any font that is available in your OS. The point here is that we are feeding our &#8220;extended&#8221; DrawText method with the sample text and the alignment we want to use in for drawing it both in the graphic context of a Picture and the one from a PDFDocument instance. Also, CustomDesktopCanvas1 is a simple Canvas subclass with an &#8220;image&#8221; property added to it as a computed property, so when a new value is assigned it will refresh itself and the Paint event will draw the picture centered in the canvas.</p>



<div class="wp-block-image is-style-default"><figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="838" src="https://blog.xojo.com/wp-content/uploads/2022/05/AlignmentMacOS-1024x838.png" alt="" class="wp-image-10352" srcset="https://blog.xojo.com/wp-content/uploads/2022/05/AlignmentMacOS-1024x838.png 1024w, https://blog.xojo.com/wp-content/uploads/2022/05/AlignmentMacOS-300x245.png 300w, https://blog.xojo.com/wp-content/uploads/2022/05/AlignmentMacOS-768x628.png 768w, https://blog.xojo.com/wp-content/uploads/2022/05/AlignmentMacOS-1536x1257.png 1536w, https://blog.xojo.com/wp-content/uploads/2022/05/AlignmentMacOS-2048x1675.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure></div>



<p>Run the example project and you should see something similar to the result displayed in the screenshots. Of course, there are still some details to take care of, for example when a line is split so the last letter goes over to the next line and things like that but, as mentioned in the beginning of this post, this is just a starting point. Adapt and improve upon it as needed.</p>



<p>Have fun!</p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>PDFDocument: Signing PDFs</title>
		<link>https://blog.xojo.com/2022/04/05/pdfdocument-signing-pdfs/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Tue, 05 Apr 2022 13:30:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Beginner Tips]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[Rapid Application Development]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=9937</guid>

					<description><![CDATA[Beginning with Xojo 2022r1 you can use Xojo's newPDFSignatureForm Control in your PDFDocuments. Using this allows your users to be able to sign documents using a Digital Certificate.  ]]></description>
										<content:encoded><![CDATA[
<p>Beginning with Xojo 2022r1 you can use Xojo&#8217;s new<code><a href="https://documentation.xojo.com/api/pdf/pdfsignature.html#pdfsignature">PDFSignature</a></code>Form Control in your PDFDocuments. Using this allows your users to be able to sign documents using a Digital Certificate.  Read on to learn how&#8230;</p>



<span id="more-9937"></span>



<p>Once the document has been signed and saved to disk, anyone opening the document will be able to check if the signature on the document is still valid or if, on the contrary, there have been changes to the documents after it was signed.</p>



<p>Adding signing controls to a PDF Document with this code:</p>



<pre class="wp-block-preformatted">Var d As New PDFDocument

// Creating a new PDFSignature instance
Var signatureField As PDFSignature = New PDFSignature(1, X, Y, Width, Height, "SignatureField")

// …and adding it to the Form controls in the PDFDocument instance
d.AddControl(signatureField)</pre>



<p>As you can see, you need to create a new instance from the <code>PDFSignature</code> class providing to the <code>Constructor</code> method the page number, X and Y coordinates, and the width and height values for the interactive signing box.</p>



<p>These screenshots show a PDF document with a <code>PDFSignature</code> control added before it has been signed (on the left), and after it has been signed using a Digital Certificate (on the right).  The project that produced the example below is included in the Example Projects folder in the Xojo download.</p>



<figure class="wp-block-image is-style-default"><img loading="lazy" decoding="async" width="1024" height="647" src="https://blog.xojo.com/wp-content/uploads/2022/02/PDFSigning-1024x647.png" alt="" class="wp-image-9940" srcset="https://blog.xojo.com/wp-content/uploads/2022/02/PDFSigning-1024x647.png 1024w, https://blog.xojo.com/wp-content/uploads/2022/02/PDFSigning-300x189.png 300w, https://blog.xojo.com/wp-content/uploads/2022/02/PDFSigning-768x485.png 768w, https://blog.xojo.com/wp-content/uploads/2022/02/PDFSigning-1536x970.png 1536w, https://blog.xojo.com/wp-content/uploads/2022/02/PDFSigning-2048x1293.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Lastly, and as it happens with many other features of the PDF format specification, the ability to digitally sign the PDF documents created with the <code>PDFDocument</code> class is up to the PDF viewer you use. For example, the free app Adobe Acrobat Reade<strong>r</strong> does support this feature, while that is not the case with the Preview app provided by macOS.</p>



<p><em>Paul learned to program in BASIC at age 13 and has programmed in more languages than he remembers, with Xojo being an obvious favorite. When not working on Xojo, you can find him talking about retrocomputing at <a href="https://goto10.substack.com" target="_blank" rel="noreferrer noopener">Goto 10</a> and </em>on Mastodon @lefebvre@hachyderm.io.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>PDFDocument: Font Handling Improvements</title>
		<link>https://blog.xojo.com/2022/04/05/pdfdocument-font-handling-improvements/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Tue, 05 Apr 2022 13:30:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Font]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Multi-Platform Development]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[Rapid Application Development]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=9942</guid>

					<description><![CDATA[Xojo 2022r1 brings a bunch of font handling improvements plus new features to the creation of PDF documents. As you probably know, the best way&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Xojo 2022r1 brings a bunch of font handling improvements plus new features to the creation of PDF documents.</p>



<span id="more-9942"></span>



<p>As you probably know, the best way to stay in the &#8220;safe zone&#8221; when using fonts in your PDF files is to use only the Standard 14 fonts: Helvetica, Times, Courier, Zapf Dingbats and Symbol. As part of the PDF standard, these fonts are as close to a &#8220;guarantee&#8221; that the operating system will display the text correctly without needing to embed any fonts as part of the PDF file. As result, the PDF files are smaller when you use on the Standard 14.</p>



<p>But, of course, there are times you need to include more visually captivating fonts in your PDF documents. In these cases, you can use fonts that are already available (installed) in the Fonts folder on the OS. But if you want to use fonts that aren&#8217;t available by default to the Operating System, PDFDocument has improved in this regard in Xojo 2022r1. </p>



<p>First, the fonts cache manager has been improved for speed, decreasing the time required to access and get the font data even when it&#8217;s the first time to be used in text drawing on the PDF document. But not all Operating Systems include the fonts required by the PDF Standard 14, and PDFDocument requires that any font you want to use be installed in the computer/device (or added using AddFonts). Follow these tips:</p>



<ul class="wp-block-list">
<li><strong>macOS</strong> includes by default all the fonts required by the PDF Standard 14, except Monterrey. Where Times is not installed you can use Times New Roman.</li>



<li><strong>Windows</strong> doesn&#8217;t includes Helvetica, Times, Courier or ZapfDingbats. You can use Arial, Times New Roman, Courier New&nbsp;and install ZapfDingbats or any similar font you want to use.</li>



<li><strong>Linux</strong> doesn&#8217;t includes any of the Standard 14 fonts, but you can use some that are equivalent and are installed by default in most of the Linux distributions: Liberation Sans instead of Helvetica, Liberation Serif instead of Times and Liberation Mono instead of Courier. You can install the Symbol and ZapfDingabts font files or any that is equivalent to these.</li>
</ul>



<p>In addition, it is typical for Linux based servers not to have many fonts installed; make sure to install all the font files you intend to use in the creation of your PDF documents.</p>



<h2 class="wp-block-heading">Embedding the Fonts in the PDF</h2>



<p>On the other hand, and because this was a feature requested by several users, we have brought back the EmbeddedFonts property (set by default to False). This way, when you use any font not included among the Standard 14 ones, the data of that fonts won&#8217;t be included either as part of the PDF contents, resulting, thus, in smaller PDF files.</p>


<div class="wp-block-image size-large wp-image-9944 is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="606" src="https://blog.xojo.com/wp-content/uploads/2022/02/PDFFileSize-1024x606.png" alt="" class="wp-image-9944" srcset="https://blog.xojo.com/wp-content/uploads/2022/02/PDFFileSize-1024x606.png 1024w, https://blog.xojo.com/wp-content/uploads/2022/02/PDFFileSize-300x177.png 300w, https://blog.xojo.com/wp-content/uploads/2022/02/PDFFileSize-768x454.png 768w, https://blog.xojo.com/wp-content/uploads/2022/02/PDFFileSize-1536x908.png 1536w, https://blog.xojo.com/wp-content/uploads/2022/02/PDFFileSize-2048x1211.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">This three pages PDF document uses more than 150 fonts, keeping its file size to just 268 KB.</figcaption></figure>
</div>


<p>This feature is especially useful for sharing PDFs with people that have the same set of fonts installed in their OSs, as it is the case in many companies. Additionally, using EmbeddedFonts can considerably reduce the size of the PDFs.</p>



<p>But if the PDF documents created this way are distributed for public or general use, then the end user won&#8217;t have the exact same set of fonts used during the creation of the PDF and, as result, those not available fonts will be substituted and the text won&#8217;t render as expected or was initially designed to (including fonts metrics and styles).</p>



<p>If, on the contrary, the EmbeddedFonts is set to True, then the PDF document will include all the required font information (excluding the data for those in the Standard 14 set) in order to render properly the text, both if the user has those fonts installed or not.</p>



<h2 class="wp-block-heading">Using Fonts Not Installed in the Operating System</h2>



<p>The PDFDocument.AddFonts method has been generally improved and now includes the ability to use fonts <em>not</em> installed when creating PDF Documents in iOS apps created with Xojo.</p>



<p>In this example, I recommend setting the PDFDocument.AddFonts property to True in order to guarantee that the required font data is included as part of the PDF document itself.</p>



<p>Take into consideration the following:</p>



<ol class="wp-block-list">
<li><strong>While using external fonts on Windows</strong>&#8211; Provide AddFonts with a FolderItem pointing to the directory containing the font files.</li>



<li><strong>While using external fonts on macOS</strong>&#8211; macOS requires copying to the Resources &gt; Fonts folder, inside the app bundle, for any font you want to use that is not among those available in the Fonts folder. To do this, add a &#8220;Copy Files&#8221; compilation step to your Xojo project, copying all the fonts you are going to use inside the &#8220;Fonts&#8221; subdirectory and select &#8220;Resources&#8221; as the option in the &#8220;Destination&#8221; entry form the Inspector Panel. In addition, add a text file to the project in the Xojo Navigator (for example named &#8220;ExtraKeys.plist&#8221;) with  the following text: <pre>&lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd"&gt; &lt;plist version="0.9"&gt; &lt;dict&gt; &lt;key&gt;ATSApplicationFontsPath&lt;/key&gt; &lt;string&gt;Fonts&lt;/string&gt; &lt;/dict&gt; &lt;/plist&gt;</pre> </li>



<li><strong>While using external fonts on iOS</strong>&#8211; As it is the case with macOS, iOS requires copying any fonts you want to use in your PDF and that aren&#8217;t already installed to the &#8220;App Parent Folder&#8221;. To do this, add a &#8220;Copy Files&#8221; compilation step to your Xojo project, copying all the font files inside the &#8220;Fonts&#8221; subdirectory, and selecting &#8220;App Parent Folder&#8221; as the Destination in the associated Inspector Panel. In addition, add a text file to your Xojo project (for example named &#8220;iOSKeys.plist&#8221;) whose content will be similar to this: <pre>&lt;?xml version="1.0" encoding="UTF-8"?> &lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> &lt;plist version="1.0"> &lt;dict> &lt;key>UIAppFonts&lt;/key> &lt;array> &lt;string><strong>Honey.ttf</strong>&lt;/string> &lt;string><strong>Montserrat-Regular.otf</strong>&lt;/string> &lt;string><strong>Gypsum.ttf</strong>&lt;/string> &lt;/array> &lt;/dict> &lt;/plist>Notice how, in this example, the "Honey.ttf", "Montserrat-Regular.otf" and "Gypsum.ttf" entries are the name of the font files that will be added to the iOS app using the Copy Files compilation step. You'll need to change that names for the font files you're going to use (including the file extension) and make sure that the ".plist" file has as many of these entries as the amount of fonts added to the project using the Copy files compilation step.</pre> <figure><img loading="lazy" decoding="async" width="207" height="300" class="wp-image-9943 size-medium aligncenter" src="https://blog.xojo.com/wp-content/uploads/2022/02/iOSFonts-207x300.png" alt="" srcset="https://blog.xojo.com/wp-content/uploads/2022/02/iOSFonts-207x300.png 207w, https://blog.xojo.com/wp-content/uploads/2022/02/iOSFonts-707x1024.png 707w, https://blog.xojo.com/wp-content/uploads/2022/02/iOSFonts.png 750w" sizes="auto, (max-width: 207px) 100vw, 207px" /></figure> <p>For example, this screenshot shows a PDF created on iOS that uses the fonts named in the previous &#8220;.plist&#8221; file.<span style="font-size: 1em;"> </span></p></li>
</ol>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>PDFDocument: Reports With Full Vectorial Quality</title>
		<link>https://blog.xojo.com/2022/04/05/pdfdocument-reports-with-full-vectorial-quality/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Tue, 05 Apr 2022 13:30:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Multi-Platform Development]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[Rapid Application Development]]></category>
		<category><![CDATA[Report Editor]]></category>
		<category><![CDATA[Reporting]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Xojo API 2.0]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=9948</guid>

					<description><![CDATA[Back in 2020 when PDFDocument was first introduced in Xojo, we had to make a compromise in order to render the output created via Xojo&#8217;s&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Back in 2020 when <a href="https://documentation.xojo.com/api/pdf/pdfdocument.html#pdfdocument">PDFDocument</a> was first introduced in Xojo, we had to make a compromise in order to render the output created via Xojo&#8217;s integrated <a href="https://documentation.xojo.com/topics/printing/the_report_editor/index.html#the-report-editor">Report Editor</a>. That was far from ideal, but we needed to first meet some other requirements in order to get the full vectorial quality you expect in both PDFs as well as in rendering reports.</p>



<p>With Xojo 2022r1 I am happy to say we have achieved that goal! The best part is that you don&#8217;t need to do anything to take advantage of the update. Keep your code as it is now and, the next time you output your report into a PDF document you&#8217;ll get the full vectorial quality you expect!</p>



<span id="more-9948"></span>


<div class="wp-block-image wp-image-9949 size-large is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="355" src="https://blog.xojo.com/wp-content/uploads/2022/02/PDFReports-1024x355.png" alt="" class="wp-image-9949" srcset="https://blog.xojo.com/wp-content/uploads/2022/02/PDFReports-1024x355.png 1024w, https://blog.xojo.com/wp-content/uploads/2022/02/PDFReports-300x104.png 300w, https://blog.xojo.com/wp-content/uploads/2022/02/PDFReports-768x267.png 768w, https://blog.xojo.com/wp-content/uploads/2022/02/PDFReports-1536x533.png 1536w, https://blog.xojo.com/wp-content/uploads/2022/02/PDFReports-2048x711.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption><strong>From left to right:</strong> PDF Report output using Xojo 2021r3.1, same report output using Xojo 2022r1, and an area of that PDF Zoomed at 400% in the Viewer app.</figcaption></figure>
</div>


<p>As you can see, the difference is quite notable. Additionally, because the new Reports rendering is full vectorial quality, that means that you will be able to select the text or even using the Search capability provided by your PDF viewer app.</p>



<p><em>Paul learned to program in BASIC at age 13 and has programmed in more languages than he remembers, with Xojo being an obvious favorite. When not working on Xojo, you can find him talking about retrocomputing at <a href="https://goto10.substack.com" target="_blank" rel="noreferrer noopener">Goto 10</a> and </em>on Mastodon @lefebvre@hachyderm.io.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>PDFDocument: More PDFGraphics Enhancements</title>
		<link>https://blog.xojo.com/2022/04/05/pdfdocument-more-pdfgraphics-enhancements/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Tue, 05 Apr 2022 13:30:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Graphics]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=9959</guid>

					<description><![CDATA[With the added functionality of the Brush property and the ClipToPath, Clip and DrawObject methods, Xojo 2022r1 completes the practical PDFGraphics class support for all the methods and properties that makes sense (or are applicable) from Xojo's Graphics class. ]]></description>
										<content:encoded><![CDATA[
<p>With the added functionality of the <a href="https://documentation.xojo.com/api/graphics/graphics.html#graphics-brush">Brush</a> property and the <a href="https://documentation.xojo.com/api/graphics/graphics.html#graphics-clipToPath">ClipToPath</a>, <a href="https://documentation.xojo.com/api/graphics/graphics.html#graphics-clip">Clip</a> and <a href="https://documentation.xojo.com/api/graphics/graphics.html#graphics-drawobject">DrawObject</a> methods, Xojo 2022r1 completes the practical <a href="https://documentation.xojo.com/api/pdf/pdfgraphics.html">PDFGraphics</a> class support for all the methods and properties that makes sense (or are applicable) from Xojo&#8217;s <a href="https://documentation.xojo.com/api/graphics/graphics.html">Graphics</a> class. </p>



<h3 class="wp-block-heading">Fillings and Drawing with Brush</h3>



<p>The Brush property allows you to assign, well, a brush to the current Graphics context in order to use it as the drawing color or filling for any of the available shapes when drawing text and also in drawing vectorial paths into the PDF document. When the Brush property is set to Nil, then the color set via DrawingColor will be applied.</p>



<p>What makes the Brush property especially interesting is that you can assign to it any instance created from the <a href="https://documentation.xojo.com/api/graphics/picture.htmlBrush">PictureBrush</a>, <a href="https://documentation.xojo.com/api/graphics/lineargradientbrush.html">LinearGradientBrush</a> or <a href="https://documentation.xojo.com/api/graphics/radialgradientbrush.html">RadialGradientBrush</a> classes.</p>



<ul class="wp-block-list"><li><strong>PictureBrush.</strong> PDFGraphics only supports the Tile, so the picture will be repeated until completing the filling area.</li><li><strong>LinearGradientBrush.</strong> PDFGraphics offers the same support you expect when it is used in combination with the regular Graphics class.</li><li><strong>RadialGradientBrush.</strong> PDFGraphics offers the same support you expect when it is used in combination with the regular Graphics class.</li></ul>



<p>The following image shows a PDF with PictureBrush applied as the color for the text, RadialGradientBrush set to fill the lower rectangle, and also as the outline color for drawing the &#8220;The Golden&#8221; text. Additionally, a LinearGradientBrush is used to fill the upper rectangle. The graphic context has been set to use a transparency value when drawing the text, so it also affect the transparency of the filling brush on these.</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="462" src="https://blog.xojo.com/wp-content/uploads/2022/02/PDFGradient-1024x462.png" alt="" class="wp-image-9960" srcset="https://blog.xojo.com/wp-content/uploads/2022/02/PDFGradient-1024x462.png 1024w, https://blog.xojo.com/wp-content/uploads/2022/02/PDFGradient-300x135.png 300w, https://blog.xojo.com/wp-content/uploads/2022/02/PDFGradient-768x347.png 768w, https://blog.xojo.com/wp-content/uploads/2022/02/PDFGradient-1536x693.png 1536w, https://blog.xojo.com/wp-content/uploads/2022/02/PDFGradient-2048x924.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<h3 class="wp-block-heading">ClipToPath</h3>



<p>In opposition to ClipToRectangle or Clip, the ClipToPath method allows the definition of a irregular area that will act as the cropping area for any later drawing in the PDF, while ClipToRectangle and Clip provide regular areas: rectangles or squares.</p>



<p>When used in combination with PDFGraphics , expect the same behavior as when used in combination with a regular context from the Graphics class. For example, while the following snippet of code will draw a circle, only the portion contained in the ClipToPath set will be visible (a triangle), as you can see in the picture below from the generated PDF.</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="281" height="300" src="https://blog.xojo.com/wp-content/uploads/2022/02/PDFClipToPath-281x300.png" alt="" class="wp-image-9961" srcset="https://blog.xojo.com/wp-content/uploads/2022/02/PDFClipToPath-281x300.png 281w, https://blog.xojo.com/wp-content/uploads/2022/02/PDFClipToPath.png 726w" sizes="auto, (max-width: 281px) 100vw, 281px" /></figure>
</div>


<pre class="wp-block-preformatted">Var d As New PDFDocument
Var g As Graphics = d.Graphics

// Clip to a GraphicsPath
// Path is a triangle
Var p As New GraphicsPath
p.MoveToPoint(0, 0) // Start location
p.AddLineToPoint(20, 44)
p.AddLineToPoint(40, 0)
p.AddLineToPoint(0, 0)

g.SaveState
g.DrawingColor = Color.Red
g.ClipToPath(p)
g.FillOval(0, 0, 50, 50)
g.RestoreState

Var f As FolderItem = SpecialFolder.Desktop.Child("Cliptopath.pdf")
d.Save(f)</pre>



<h3 class="wp-block-heading">Clip: New Graphic Contexts</h3>



<p>In opposition to ClipToRectangle and ClipToPath, the Clip method is more powerful because it not only provides a cropping area but a fully new Graphic context. That is, you&#8217;ll be able to set any of the properties on the returned Graphics.Clip context and also call any of the PDFGraphics supported methods on it.</p>



<p>In this regard, all the coordinates provided for the drawing are relative to the top/left of the new Clip, and not on the main Graphics context it is based on. So, if we run the following snippet of code:</p>



<pre class="wp-block-preformatted">Var d As New PDFDocument
Var g As Graphics = d.Graphics

g.FontSize = 40
g.DrawText("Hello…", 40, 100)

// Getting a new graphics context via Clip
// We change the Font and the 
// drawing color

Var g1 As Graphics = g.Clip(40, 130, 170, 50)
g1.FontName = "Times"
g1.DrawingColor = Color.Red
g1.DrawText("…World!", 0, 0)

// Back To drawing on the main Graphics context. 
// It Is Not affected by the changes made in the graphics subcontext from Clip.

g.DrawText("(Back to Main Graphics context)", 40, 240)
</pre>



<p>We can see how the line of code <code>g1.DrawTex "…World!", 0, 0</code> provides 0,0 as the X and Y coordinates for drawing the text. That is, the top/left origin of the created clip, while these values would be 40,130 as absolute coordinates if we had used the main graphics context.</p>



<p>The PDF generated as result of the previous code is the one shown in the following picture:</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="300" height="112" src="https://blog.xojo.com/wp-content/uploads/2022/02/PDFClip-300x112.png" alt="" class="wp-image-9962" srcset="https://blog.xojo.com/wp-content/uploads/2022/02/PDFClip-300x112.png 300w, https://blog.xojo.com/wp-content/uploads/2022/02/PDFClip-1024x381.png 1024w, https://blog.xojo.com/wp-content/uploads/2022/02/PDFClip-768x285.png 768w, https://blog.xojo.com/wp-content/uploads/2022/02/PDFClip-1536x571.png 1536w, https://blog.xojo.com/wp-content/uploads/2022/02/PDFClip.png 2034w" sizes="auto, (max-width: 300px) 100vw, 300px" /></figure>
</div>


<p>Of course, you can nest as many Clips as you need. For example you can create a new Clip from a previous clip created in a previous step.</p>



<h3 class="wp-block-heading">DrawObject</h3>



<p>PDFGraphics also allows you to draw any of the objects created as instances from any of the Object2D class, and also those under the hierarchy of a Group2D object:</p>



<ul class="wp-block-list"><li><strong><a href="https://documentation.xojo.com/api/graphics/arcshape.html">ArchShape</a></strong></li><li><strong><a href="https://documentation.xojo.com/api/graphics/curveshape.html">CurveShape</a></strong></li><li><strong><a href="https://documentation.xojo.com/api/graphics/figureshape.html">FigureShape</a></strong></li><li><strong><a href="https://documentation.xojo.com/api/graphics/ovalshape.html">OvalShape</a></strong></li><li><strong><a href="https://documentation.xojo.com/api/graphics/pixmapshape.html">PixmapShape</a></strong></li><li><strong><a href="https://documentation.xojo.com/api/graphics/rect.htmlShape">RectShape</a></strong></li><li><strong><a href="https://documentation.xojo.com/api/graphics/roundrectshape.html">RoundRectShape</a></strong></li><li><strong><a href="https://documentation.xojo.com/api/graphics/textshape.html">TextShape</a></strong></li></ul>



<p>For example, the following snippet of code will create the PDF document you can see in the picture.:</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="300" height="241" src="https://blog.xojo.com/wp-content/uploads/2022/02/CurveShape-300x241.png" alt="" class="wp-image-9963" srcset="https://blog.xojo.com/wp-content/uploads/2022/02/CurveShape-300x241.png 300w, https://blog.xojo.com/wp-content/uploads/2022/02/CurveShape-1024x822.png 1024w, https://blog.xojo.com/wp-content/uploads/2022/02/CurveShape-768x616.png 768w, https://blog.xojo.com/wp-content/uploads/2022/02/CurveShape.png 1154w" sizes="auto, (max-width: 300px) 100vw, 300px" /></figure>
</div>


<pre class="wp-block-preformatted">Var c As New CurveShape
c.ControlX(0) = 120
c.ControlY(0) = -40
c.Order = 1
c.X = 10
c.Y = 100
c.X2 = 250
c.Y2 = 100

Var fx As New FigureShape
fx.AddLine(0, 100, 50, 0)
fx.AddLine(50, 0, -50, 0)
fx.Border = 100  // opaque border
fx.BorderColor = &amp;cFF0000  // red border
fx.FillColor = &amp;cFFFF00   // yellow interior

Var d As New PDFDocument

Var g As Graphics = d.Graphics
g.DrawObject(c, c.x, c.y)
g.DrawObject(fx, 100, 100)

d.Save(SpecialFolder.Desktop.Child("CurveShape.PDF"))
</pre>



<p><em>Paul learned to program in BASIC at age 13 and has programmed in more languages than he remembers, with Xojo being an obvious favorite. When not working on Xojo, you can find him talking about retrocomputing at <a href="https://goto10.substack.com" target="_blank" rel="noreferrer noopener">Goto 10</a> and </em>on Mastodon @lefebvre@hachyderm.io.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>PDFDocument: Transparency Support</title>
		<link>https://blog.xojo.com/2021/11/18/pdfdocument-transparency-support/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Thu, 18 Nov 2021 14:00:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Graphics]]></category>
		<category><![CDATA[Multi-Platform Development]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[Rapid Application Development]]></category>
		<category><![CDATA[Xojo API 2.0]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=9491</guid>

					<description><![CDATA[Among the many improvements added to PDFDocument in Xojo 2021r3 is support for Graphics.Transparency as well as support for the alpha value in the color&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Among the many improvements added to PDFDocument in Xojo 2021r3 is support for <code>Graphics.Transparency</code> as well as support for the alpha value in the color assigned to the <code>Graphics.DrawingColor</code> property. Continue reading to learn more!</p>



<p>With 2021r3 you&#8217;ll be able to effectively set and use both <code>Transparency</code> and also the <code>Color</code> alpha component in any item you add to PDF documents: text, shapes and images! Moreover, the support of the <code>Pictures</code> has been improved so <code>PDFDocument</code> will work with the alpha channel of the image, instead of considering the alpha channel of the image as a fixed white background as in previous releases. That means more flexibility in the layout of the PDFs!</p>



<figure class="wp-block-image is-style-default"><img loading="lazy" decoding="async" width="1024" height="403" src="https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-20-a-las-9.39.00-1024x403.png" alt="" class="wp-image-9492" srcset="https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-20-a-las-9.39.00-1024x403.png 1024w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-20-a-las-9.39.00-300x118.png 300w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-20-a-las-9.39.00-768x302.png 768w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-20-a-las-9.39.00-1536x604.png 1536w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-20-a-las-9.39.00.png 1672w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>And because <code>Transparency</code> support is added to PDF using the <code>Graphic</code> class you, the way to use it is very straightforward. For example, put this following snippet of code in the <code>Open</code> Event Handler for a Desktop project (in this case, the referenced &#8220;GrassBG&#8221; picture has been added to the project):</p>



<pre class="wp-block-preformatted">// Creating a new PDFDocument instance
Var d As New PDFDocument

// Getting the graphic context from the PDF Document
Var g As Graphics = d.Graphics

// How many rectangles fits in the page width?
Var iter As Integer = g.Width/10

Var x As Integer

// Let's calculate the Y coordinate for center the
// GrassBG in the height of the PDF page
Var imageY As Integer = g.Height/2 - grassBG.Height/2

// And calculate the Y coordinate for drawing the rectangles
Var y As Integer = (imagey + grassbg.Height) - 40

// Transparency value = 0
Var tLevel As Integer

// Value to increase the Transparency on every rectangle
// drawing step
Var offset As Integer = 10

Var txt As String = "Transparency"

g.FontSize = 90
g.Bold = True

// X and Y coordinates to center the "Transparency" text
// on the page width / height
Var txtX As Integer =  g.Width/2 - g.TextWidth(txt) / 2
Var txtY As Integer = ImageY + GrassBG.Height - g.FontAscent

// Drawing the "Transparency" text -&gt; Background layer!
g.DrawText txt, txtX, txty

// Drawing the GrassBG picture over the text
// that's the second layer, and preserving
// the PNG alpha channel
g.DrawPicture grassBG,0,ImageY

// Setting the initial random color for drawing
// the first rectangle
Var rd As New Random
g.DrawingColor = Color.RGB(rd.InRange(0,255), rd.InRange(0,255), rd.InRange(0,255))

Var tmpLevel, y1 As Integer

// Drawing the horizontal strip of rectangles.
// This is the third layer
For n As Integer = 0 To iter

  // Setting the Transparency value
  g.Transparency = tLevel

  // Drawing the rectangle
  g.FillRectangle x,y,20,40

  // Assign the current Transparency value to
  // tmpLevel variable in order to draw the color drops

  tmpLevel = tLevel

  // Y coordinate for the color drop
  y1 = y + 40

  // Drawing the color drops for the current Rect
  For i As Integer = 0 To 10
    tmpLevel = tmpLevel - 10
    If tmpLevel &gt;= 0 Then
      g.Transparency = tmpLevel
      g.FillRectangle x,y1,2, 2
      y1 = y1 + 2
    End If
  Next i

  // We increase the X coordinate for drawing the
  // next rectangle
  x = x + 20

  //…and increase the Transparency value by ten
  tLevel = tLevel + offset

  // we reached the maximum allowable value for
  // the transparency, so let's invert the sign
  // for the offset and set a new
  // drawing color.
  If tLevel = 100 Or tLevel = 0 Then
    offset = -offset
    g.DrawingColor = Color.RGB(rd.InRange(0,255), rd.InRange(0,255), rd.InRange(0,255))
  End If

Next n

// Let's draw the fourth layer over the strip of rectangles
// with the "Comes to PDFDocument" text.
txt = "COMES TO PDFDOCUMENT"
g.FontSize = 30

// Notice that we are setting here the alpha value for
// the color, instead of relying on the Transparency property
g.DrawingColor = Color.RGB(255,255,255,127)

g.CharacterSpacing = 20
txtX = g.Width/2 - g.TextWidth(txt) /2
txty = y + 20 + g.FontAscent/2
g.DrawText txt,txtx, txty

// Getting a FolderItem reference pointing to the
// "Transparency.PDF" file on the desktop.
Var f As FolderItem = SpecialFolder.Desktop.Child("Transparency.pdf")

// Saving the PDFDocument file
d.Save(f)
f.Open</pre>



<p>Once you run this code, it will produce the PDF with the image as it is shown at the top of this post.</p>



<p>As you can see, there are four layers to  this document with the &#8220;Transparency&#8221; text drawn in the first layer (the farthest back), followed by a PNG image whose alpha channel lets us see the non-covered portions of the text behind it.</p>



<p>Next, the image is followed by a strip of horizontal rectangles in a new layer over it, that is drawn using a variable amount of transparency.</p>



<p>Finally, in the frontmost layer, we are drawing the &#8220;Comes to PDFDocument&#8221; text making use of the alpha value in the White color set as the DrawingColor.</p>



<p>You can see how the two upper layers mixed their color / level of transparency against the ones behind them and, of course, the text drawn in the PDF document continues to be vectorial and editable.</p>



<div class="wp-block-image is-style-default"><figure class="aligncenter"><img loading="lazy" decoding="async" width="640" height="480" src="https://blog.xojo.com/wp-content/uploads/2021/10/TransparencyPDF.gif" alt="" class="wp-image-9493"/></figure></div>



<h2 class="wp-block-heading">Transparency vs. Color&#8217;s Alpha Value</h2>



<p>As you probably already know, the <code>Transparency</code> value can range from 0.0 (opaque) to 100.0 (fully transparent), while the alpha component of a Color instance can range from 0.0 (opaque) to 255.0 (fully transparent).</p>



<p>What happen when you use both kind of values in the drawings of your PDF document? Let&#8217;s suppose you did set a Transparency value of 40 while setting the alpha value of the current drawing color to 127. In that case, the alpha value of the drawing color offers a higher transparency, so that will be the value applied in the drawing (because all kind of drawings, except Pictures, are affected by the current drawing color).</p>



<p>Otherwise, if the <code>Transparency</code> value is higher than the alpha value of the current drawing color, then that will be the level of transparency applied to the drawings and, in this case, also affecting to the Pictures in the PDF document.</p>



<p>Learn more about <a href="https://documentation.xojo.com/api/pdf/pdfdocument.html">PDFDocument</a> in the Xojo Documentation. And watch this 7 minute <a href="https://youtu.be/mp9Ylu3wY4g">video tutorial</a> that demonstrates this handy new feature!</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>PDFDocument: Adding PDF Forms</title>
		<link>https://blog.xojo.com/2021/11/18/pdfdocument-adding-pdf-forms/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Thu, 18 Nov 2021 12:29:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Multi-Platform Development]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Xojo API 2.0]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=9455</guid>

					<description><![CDATA[Added to PDFDocument in Xojo 2021r3 is the ability to create PDF Forms (aka AcroForms) in your PDFs. This means that it is possible to add the following Form controls to a PDF: PDFButton, PDFTextField, PDFTextArea, PDFCheckBox, PDFRadioButton, PDFPopupMenu, PDFComboBox, PDFListBox]]></description>
										<content:encoded><![CDATA[<p>One of the new features added to PDFDocument in Xojo 2021r3 is the ability to create <strong>PDF Forms</strong> (also known as <strong>AcroForms</strong>) in your PDF documents. This means that it is possible to add the following Form controls to a PDF document:</p>
<ul>
<li>PDFButton</li>
<li>PDFTextField</li>
<li>PDFTextArea</li>
<li>PDFCheckBox</li>
<li>PDFRadioButton</li>
<li>PDFPopupMenu</li>
<li>PDFComboBox</li>
<li>PDFListBox</li>
</ul>
<p>As defined by the PDF Standard, it is only possible to add one Form to a PDF document. Also, when any of these controls are added to a PDF document they won&#8217;t provide any visual cue in the actionable area itself. This means that it is up to you to &#8220;draw&#8221; any desired visual cues, for example a rectangle or rounded rectangle surrounding a Button, TextField or TexArea control, or the text labels you want to associate with CheckBoxes or RadioButtons.</p>
<p><img loading="lazy" decoding="async" class="size-large wp-image-9456 aligncenter" src="https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-16.20.28-787x1024.png" alt="" width="787" height="1024" srcset="https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-16.20.28-787x1024.png 787w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-16.20.28-230x300.png 230w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-16.20.28-768x1000.png 768w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-16.20.28-1180x1536.png 1180w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-16.20.28-1573x2048.png 1573w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-16.20.28.png 1982w" sizes="auto, (max-width: 787px) 100vw, 787px" /></p>
<p>For example, this is how a TextField would appear when added to a page:</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-9457 aligncenter" src="https://blog.xojo.com/wp-content/uploads/2021/10/125772590-d067a427-5192-4d39-864c-6ed692d392d8.png" alt="" width="386" height="92" srcset="https://blog.xojo.com/wp-content/uploads/2021/10/125772590-d067a427-5192-4d39-864c-6ed692d392d8.png 386w, https://blog.xojo.com/wp-content/uploads/2021/10/125772590-d067a427-5192-4d39-864c-6ed692d392d8-300x72.png 300w" sizes="auto, (max-width: 386px) 100vw, 386px" /></p>
<p>As you can see, it only displays the actionable area plus the text assigned as the default value set to this&nbsp;<code>PDFTextField</code> instance.</p>
<p>And this is how it looks with a rectangle added using the&nbsp;<code>Graphics.DrawRectangle</code> method:</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-9458 aligncenter" src="https://blog.xojo.com/wp-content/uploads/2021/10/125772639-6420d320-d459-4ed8-8146-ece3c58552dd.png" alt="" width="392" height="84" srcset="https://blog.xojo.com/wp-content/uploads/2021/10/125772639-6420d320-d459-4ed8-8146-ece3c58552dd.png 392w, https://blog.xojo.com/wp-content/uploads/2021/10/125772639-6420d320-d459-4ed8-8146-ece3c58552dd-300x64.png 300w" sizes="auto, (max-width: 392px) 100vw, 392px" /></p>
<p>The way to add any of these Form controls to a PDFDocument instance is quite simple; call the <code>AddControl</code> method in the <code>PDFDocument</code> instance passing along any of the supported PDF control instances.</p>
<p>About the behavior of these controls, it is worth mentioning the following cases.</p>
<h3>PDFButton</h3>
<p>You can add new instances to the Form based on this class to get the following Actions:</p>
<ul>
<li><code>PDFButton.Actions.ResetAction </code>resets the controls added to the form to their default values (if any)</li>
<li><code>PDFButton.Actions.SendForm</code>&nbsp;sends the values entered/selected by the user in the Form controls as a series of Key/Value pairs, where the Key is the name of the control, and the value sent is the entered/selected value. This data will be sent to the URL endpoint set to the URL property of the <code>PDFButton</code> instance.&nbsp;<span style="font-size: revert;">For example, a valid URL could be &#8220;http://127.0.0.1:8080&#8221;, &#8220;https://myDomain.com/WebService&#8221; or &#8220;mailto://someEmailAddress@here.com&#8221;. If the URL is a &#8220;mailto:&#8221;, then the receiver will get these values as a text file attached to the email message itself.</span></li>
<li><code>PDFButton.Actions.SendPDFFile</code>&nbsp;the endpoint url will receive the PDF file itself both when using a &#8220;mailto:&#8221; or &#8220;http(s)//&#8221; protocol.</li>
</ul>
<p><img loading="lazy" decoding="async" class="wp-image-9472 size-large" src="https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-16.21.12-835x1024.png" alt="" width="835" height="1024" srcset="https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-16.21.12-835x1024.png 835w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-16.21.12-245x300.png 245w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-16.21.12-768x942.png 768w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-16.21.12.png 920w" sizes="auto, (max-width: 835px) 100vw, 835px" /></p>
<p>It is very important to note that not all the PDF viewer apps support these actions. For example, the Preview app on macOS doesn&#8217;t support them. So it is advisable to use the free Adobe Acrobat Reader DC available on every operating system.</p>
<h3>PDFRadioButton</h3>
<p>You can add PDFRadio button to the PDF form as an individual button or as a group. When it is added as an individual RadioButton it is only possible to select/deselect it, while when used as a RadioButton group, the activation of any of the RadioButtons will disable the other RadioButtons in the group.&nbsp;</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-9459 size-thumbnail" src="https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-16.32.24-150x150.png" alt="" width="150" height="150"></p>
<p>The way to configure a RadioButton instance as a member of a group is by using the same name. For example, the following code:</p>
<pre>Var rBtn1GroupA As New PDFRadioButton(1, 200, 450, 15,15,"GroupA","OptionA")
Var rBtn2GroupA As New PDFRadioButton(1, 200, 470, 15, 15,"GroupA", "OptionB")
rBtn2GroupA.Value = True
d.AddControl(rBtn1GroupA)
d.AddControl(rBtn2GroupA)</pre>
<p>This will create two <code>PDFRadioButton</code> instances named <code>rBtn1GroupA</code> and <code>rBtn2Group2</code> sharing the same name &#8220;GroupA&#8221; but using different values: &#8220;OptionA&#8221; and &#8220;OptionB&#8221;. Also, the <code>rBtn2GroupA</code> instance is set as the default RadioButton:</p>
<pre>rBtn2GroupA.Value = True</pre>
<p>Because it is only possible to create one Form per PDF document, it doesn&#8217;t matter that the <code>RadioButton</code> instances pertaining to a same group are in all the PDF document pages; they will continue behaving as members of the same group.</p>
<h2>PDFPopupMenu and PDFComboBox</h2>
<p>These controls behave similar to what you expect in any Xojo project. You can populate them with a series of default options and set one of them as the selected option displayed by default. The main difference is that a <code>PDFComboBox</code> lets the user type text that is not available among the assigned options.</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-9460 size-medium" src="https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-16.33.40-300x82.png" alt="" width="300" height="82" srcset="https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-16.33.40-300x82.png 300w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-16.33.40-1024x280.png 1024w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-16.33.40-768x210.png 768w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-16.33.40.png 1060w" sizes="auto, (max-width: 300px) 100vw, 300px" /></p>
<p>For example, the following fragment of code will create a <code>PDFPopupMenu</code> instance:</p>
<pre>Var cPopup As New PDFPopupMenu(1,210,540,100,15,"List","Option A", "Option B", "Option C", "Option D")
d.AddControl(cPopup)</pre>
<p>Here &#8220;List&#8221; is the name of the control itself and &#8220;Option A&#8221;, &#8220;Option B&#8221;, &#8220;Option C&#8221; and &#8220;Option D&#8221; are the values that will be presented as the menu options to the user.</p>
<p>Of course you can also pass along the <code>PDFPopupMenu</code> options as a String Array to the Constructor if you want:</p>
<pre>Var r() As String = Array("Option A", "Option B", "Option C", "Option D")
Var cPopup As New PDFPopupMenu(1,210,540,100,15,"List",r)
d.AddControl(cPopup)</pre>
<p>Creating a <code>PDFComboBox</code> instance is similar. For example:</p>
<pre>Var cCombo As New PDFComboBox(1,100,540,100,15,"ListC","Option A", "Option B", "Option C", "Option D")
cCombo.SelectedRowValue = "Option C"
d.AddControl(cCombo)</pre>
<p>In this case, &#8220;Option C&#8221; will be the value selected by default.</p>
<h2>PDFListBox</h2>
<p>There is not much difference about how the PDFListBox instances are created, when compared with a <code>PDFPopupMenu</code> or <code>PDFComboBox</code>:</p>
<pre>Var options() As String = Array("Option A", "Option B", "Option C", "Option D")
Var cListBox As New PDFListBox(1,320,540,100,90,"ListB", options)
cListBox.RowSelectionType = PDFListBox.RowSelectionTypes.Multiple
cListBox.SelectedRowValue = "Option D"
d.AddControl(cListBox)</pre>
<p>As you can see, in this case the value selected by default will be &#8220;Option D&#8221;. The main difference is that a <code>PDFListBox</code> allows you to set the <code>RowSelectionType</code> between &#8220;Multiple&#8221; and &#8220;Single&#8221; as is the case when using the DesktopListBox in a regular Xojo project. So, in this case, you can tell the <code>cListBox</code> instance to allow the user to select multiple entries in the control:</p>
<pre>cListBox.RowSelectionType = PDFListBox.RowSelectionTypes.Multiple</pre>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-9461 size-medium" src="https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-16.34.29-300x281.png" alt="" width="300" height="281" srcset="https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-16.34.29-300x281.png 300w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-16.34.29.png 524w" sizes="auto, (max-width: 300px) 100vw, 300px" /></p>
<p>One thing to note is that when the PDF is sent to an endpoint URL using the <code>SendForm</code> kind of <code>Action</code>, multiple options will be represented as a repeated series of Key/Value pairs with the same Key name. For example, let&#8217;s say that the user selects the &#8220;Option B&#8221;, &#8220;Option C&#8221; and &#8220;Option D&#8221; values. Then, the endpoint webservice will receive:</p>
<pre>ListB=Option+B&amp;ListB=Option+C&amp;ListB=Option+D</pre>
<p>Notice how in all these cases &#8220;ListB&#8221; is the same name given to our <code>PDFListBox</code> instance.</p>
<h2>PDFTextField and PDFTextArea</h2>
<p>There are a couple of interesting properties you can set on the instances created from these classes:</p>
<ul>
<li><code>ReadOnly</code>: Set this property to <code>True</code> so the user can&#8217;t type on the control.</li>
<li><code>MaximumCharactersAllowed</code>: Set this property to the maximum number of characters that the user is allowed to type in the control.</li>
</ul>
<p>This fragment of code will create a <code>PDFTextField</code> instance:</p>
<pre>Var tf As New PDFTextField(1, 100, 50, 200, 22, "TextField", "Some sample text")
d.AddControl(tf)</pre>
<p>&#8220;TextField&#8221; is the name of the control instance, and &#8220;Some sample Text&#8221; is the displayed default value.</p>
<p>And this is how we can create a <code>PDFTextArea</code> instance setting the maximum of allowed characters to 100:</p>
<pre>Var ta As New PDFTextArea(1, 100, 100, 200, 300, "TextArea", "Hi There!")
ta.MaximumCharactersAllowed = 100
d.AddControl(ta)</pre>
<p>&#8220;TextArea&#8221; is the name of the control instance and &#8220;Hi There!&#8221; is the displayed by default value.</p>
<h2>Summary</h2>
<p>Now you can see how easy it is to add Forms to your PDF documents created with Xojo! If you want to learn more about how these work and also play with the different Action modes, you can run the PDFFormTest-Desktop Xojo project found in the Example Projects &gt; PDF folder and see the <a href="https://documentation.xojo.com/api/pdf/pdfdocument.html">Xojo Documentation</a>.</p>


<p><em>Paul learned to program in BASIC at age 13 and has programmed in more languages than he remembers, with Xojo being an obvious favorite. When not working on Xojo, you can find him talking about retrocomputing at <a href="https://goto10.substack.com" target="_blank" rel="noreferrer noopener">Goto 10</a> and </em>on Mastodon @lefebvre@hachyderm.io.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>PDFDocument: No More Blurry Images</title>
		<link>https://blog.xojo.com/2021/11/18/pdfdocument-no-more-blurry-images/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Thu, 18 Nov 2021 12:00:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Graphics]]></category>
		<category><![CDATA[PDF]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=9561</guid>

					<description><![CDATA[Among the major enhancements made to the images support in PDFDocument in Xojo 2021r3 release, in addition to transparency support, alpha channel support, and the new way the data is codified in the resulting PDF stream (no more DCTEncoding), we've also tackled an issue with images not being as sharp as they should have been. ]]></description>
										<content:encoded><![CDATA[
<p>Among the major enhancements made to the images support in <code>PDFDocument</code> in Xojo 2021r3 release, in addition to <a href="https://blog.xojo.com/2021/11/16/pdfdocument-transparency-support">transparency support</a>, alpha channel support, and the new way the data is codified in the resulting PDF stream (no more DCTEncoding), we&#8217;ve also tackled an issue with images not being as sharp as they should have been. </p>



<span id="more-9561"></span>



<p>With Xojo 2021r3 we are handling the images added to <code>PDFDocument</code> in a different way. When images are added to the page using a smaller size than the original size, which is probably more common, using something like:</p>



<pre class="wp-block-preformatted">Var d As New PDFDocument
var g as Graphics = d.Graphics

g.DrawPicture myImage, 10, 10, 100, 100, 0, 0, myImage.Width, myImage.Height</pre>



<p>or</p>



<pre class="wp-block-preformatted">g.DrawPicture myImage, 10, 10, myImage.Width/3, myImage.Width/3, 0, 0, myImage.Width, myImage.Height</pre>



<p>&#8220;myImage&#8221; being an image added to the Xojo project, loaded from disk or from a database query.</p>



<p>You can appreciate how the quality has improved from left to right, below.</p>



<figure class="wp-block-image size-large is-style-default"><img loading="lazy" decoding="async" width="1024" height="576" src="https://blog.xojo.com/wp-content/uploads/2021/11/Untitled-design-1024x576.png" alt="" class="wp-image-9577" srcset="https://blog.xojo.com/wp-content/uploads/2021/11/Untitled-design-1024x576.png 1024w, https://blog.xojo.com/wp-content/uploads/2021/11/Untitled-design-300x169.png 300w, https://blog.xojo.com/wp-content/uploads/2021/11/Untitled-design-768x432.png 768w, https://blog.xojo.com/wp-content/uploads/2021/11/Untitled-design-1536x864.png 1536w, https://blog.xojo.com/wp-content/uploads/2021/11/Untitled-design.png 1600w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Also, the new way the image PDF streams are created in order to get this sharpness means that all the data of the source image is added to the PDF document. In other words, it will increase its size. Comparing the same document, the one created with Xojo 2021r2.1 is 521 KB, and the one created with Xojo 2021r3 is 3.1 MB. This is because adding the full size of the the image takes a total of 950 KB, plus support for alpha and masks&#8230;</p>



<p>But the good side of the extra document size is that, because images are embedded at their full resolution, they will keep looking sharp even when the PDF document is displayed beyond 100% its original scale.  You can see in the PDF document below created with Xojo 2021r2.1:</p>



<figure class="wp-block-image is-style-default"><img loading="lazy" decoding="async" width="1024" height="704" src="https://blog.xojo.com/wp-content/uploads/2021/11/Zoom_Farm_r2_1-1024x704.png" alt="" class="wp-image-9566" srcset="https://blog.xojo.com/wp-content/uploads/2021/11/Zoom_Farm_r2_1-1024x704.png 1024w, https://blog.xojo.com/wp-content/uploads/2021/11/Zoom_Farm_r2_1-300x206.png 300w, https://blog.xojo.com/wp-content/uploads/2021/11/Zoom_Farm_r2_1-768x528.png 768w, https://blog.xojo.com/wp-content/uploads/2021/11/Zoom_Farm_r2_1-1536x1056.png 1536w, https://blog.xojo.com/wp-content/uploads/2021/11/Zoom_Farm_r2_1-2048x1408.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>And the PDF document created with Xojo 2021r3:</p>



<figure class="wp-block-image is-style-default"><img loading="lazy" decoding="async" width="1024" height="704" src="https://blog.xojo.com/wp-content/uploads/2021/11/Zoom_Farm_r3-1024x704.png" alt="" class="wp-image-9567" srcset="https://blog.xojo.com/wp-content/uploads/2021/11/Zoom_Farm_r3-1024x704.png 1024w, https://blog.xojo.com/wp-content/uploads/2021/11/Zoom_Farm_r3-300x206.png 300w, https://blog.xojo.com/wp-content/uploads/2021/11/Zoom_Farm_r3-768x528.png 768w, https://blog.xojo.com/wp-content/uploads/2021/11/Zoom_Farm_r3-1536x1056.png 1536w, https://blog.xojo.com/wp-content/uploads/2021/11/Zoom_Farm_r3-2048x1408.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h3 class="wp-block-heading">Document Size vs Image Quality</h3>



<p>The  winner of this battle depends what do you want to offer to your users. Using our example document we have the following figures:</p>



<ul class="wp-block-list"><li>PDF document resolution (w x h): 612 x 792 pixels</li><li>The apple image resolution (w x h): 607 x 576 pixels</li></ul>



<p>As you can see, the apple image has nearly the same resolution that the full page of the PDF Document! But it is rendered at a final size of 100 x 100 pixels. That means that the image will keep sharper even if we use a zoom value of 800% in the viewer app, but that has a cost in the size of the generated PDF document.</p>



<p>You&#8217;ll probably want to keep the images added to the <code>PDFDocument</code> pages at a maximum of twice the final width and height. That will produce good looking images in your PDF documents while keeping the document to a reasonable size. Learn more about PDFDocument and what&#8217;s new in the <a href="https://documentation.xojo.com/api/pdf/pdfdocument.html">Xojo Documentation</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>PDFDocument: Tips for Using Templates</title>
		<link>https://blog.xojo.com/2021/11/18/pdfdocument-tips-for-using-templates/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Thu, 18 Nov 2021 12:00:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[Rapid Application Development]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Xojo API 2.0]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=9474</guid>

					<description><![CDATA[The PDF Template is not a new feature, but it received a shine in Xojo 2021r3. What's a PDFDocument template or why would you use them? Let's look at a couple of scenarios where them are useful including storage, saving time and visual PDF editors.]]></description>
										<content:encoded><![CDATA[
<p>The PDF Template is not a new feature, but it received a shine in Xojo 2021r3. What&#8217;s a PDFDocument template or why would you use them? Let&#8217;s look at a couple of scenarios where them are useful including storage, saving time and visual PDF editors.</p>



<span id="more-9474"></span>



<h3 class="wp-block-heading">For Storage</h3>



<p>Sure, you can save a PDF created from a PDFDocument instance, as a file <em>or</em> to a database as a binary blob; but you&#8217;ll probably save a bunch of bytes if you save the <code>JSON</code> representation of the PDF document provided by the <code>PDFDocument.Template</code> method.</p>



<p>Let&#8217;s suppose you want to save these as simple &#8220;templates&#8221; for your app&#8217;s/solutions purposes. The main difference is that if you save these as PDF files, you won&#8217;t be able to add new objects / drawing / text or anything PDF-related to them&nbsp;because PDFDocument can&#8217;t parse or recreate the required objects from the data streams in the PDF file, so they won&#8217;t be able to continue to work with these.</p>



<p>On the contrary, if you save these &#8220;templates&#8221; to a file or Database using the Template method, you&#8217;ll later be able to create a new PDFDocument instance. All you need to do is pass along the saved JSON data to the PDFDocument constructor&nbsp;and voilà! Now you can continue adding new stuff to that new PDFDocument instance: from text to shapes, images, forms or new pages- anything that is supported by PDFDocument.</p>



<h3 class="wp-block-heading">Because you don&#8217;t want to draw all the stuff again</h3>



<p>A new PDFDocument instance created from the data received through the <code>Template</code> method means that there is not need to &#8220;draw&#8221; the PDF again from scratch using Xojo code. The PDFDocument constructor will take care of the all the needed steps in order to recreate the required objects from the received data.</p>



<p>You may think, &#8220;Well, my app already has the code needed to draw that same PDF documents&#8221;. Maybe that&#8217;s true for some scenarios, but not for all.</p>



<p>For example, what about a solution whose main app is in charge of drawing these base PDF documents or &#8220;templates&#8221; via code, later saving them to a database? Then, the client app will be able to simply get the PDF &#8220;template&#8221; they need from the database, create a new PDFDocument instance from that data, and add all the new stuff they need …&nbsp;<em>without</em> relying in the code that was needed to create the base PDF document in first place.</p>



<h3 class="wp-block-heading">You want to offer a visual PDF Editor to your users</h3>



<p>Maybe you are thinking about offering your users a visual editor so they can create PDF documents by simply dragging and dropping controls from a panel, just as you do when working with the Layout Editor in the Xojo IDE.</p>



<p>In this case, it is  really worth offering your users an option so they can save the PDF document in its current state for a later retrieval; like you would expect from any editor out there in 2021. In that case, and thanks to the <code>PDFDocument.Template</code> method, that is quite easy! Call the method on the PDFDocument instance and save the retrieved JSON data in the file format or database engine you want.</p>



<p>Your users will be able to run your app again a few hours or days, retrieve any of the PDF documents they previously saved and continue working on them in the same point they left!</p>



<h3 class="wp-block-heading">Quick Example: Working With PDFDocument.Template</h3>



<p>Let&#8217;s put this feature in practice with a simple example. This example isn&#8217;t that useful for a real-world app, but it serves to demonstrate well how <code>PDFDocument.Template</code> works.</p>



<p>So, let&#8217;s start with a code snippet that will create a really simple <code>PDFDocument</code>; just some text and a circle in a one-page document:</p>



<pre class="wp-block-preformatted">Var d As New PDFDocument

Var g As Graphics = d.Graphics

g.FontSize = 30
g.DrawText "Hello there!", 50, 100

Var x, y As Double

x = g.Width/2 - 100
y = g.Height/2 - 100

g.DrawingColor = Color.Red
g.Transparency = 50.0

g.FillOval(x,y,200,200)

Var f As FolderItem = SpecialFolder.Desktop.Child("SamplePDF.pdf")
d.Save(f)
f.Open</pre>



<p>This is the how that PDF document will look; not too impressive, but it works for the example purpose:</p>



<div class="wp-block-image is-style-default"><figure class="aligncenter"><img loading="lazy" decoding="async" width="234" height="300" src="https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-20.00.53-234x300.png" alt="" class="wp-image-9475" srcset="https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-20.00.53-234x300.png 234w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-20.00.53-799x1024.png 799w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-20.00.53-768x984.png 768w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-20.00.53-1198x1536.png 1198w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-20.00.53.png 1264w" sizes="auto, (max-width: 234px) 100vw, 234px" /></figure></div>



<p>Now let&#8217;s add a line of code to get the &#8220;template&#8221; data from that document:</p>



<pre class="wp-block-preformatted">Var template As JSONItem = d.Template</pre>



<p>And this is how the JSON data will look for that document:</p>



<pre class="wp-block-preformatted">{"General":{"Author":"","Creator":"Xojo","Keywords":"","Subject":"","Title":""},"Document":{"Compression":true,"EmbeddedFonts":false,"Landscape":false,"Width":612.0,"Height":792.0},"Actions":{"0":{"FontSize":"30.00"},"1":{"DrawText":"Hello there!,_ENDTEXT_,50.00,100.00,.00,False"},"2":{"Color":"&amp;h00FF0000"},"3":{"Transparency":".50"},"4":{"FillOval":"206.00,296.00,200.00,200.00"}},"Images":{}}</pre>



<p>A mere 396 bytes if we decide to save that data as text to a file. In comparison, our example PDF file is 1,380 bytes in length at this point.</p>



<p>Now let&#8217;s create a new <code>PDFDocument</code> instance from that template. All we need is to add this line to the existing code:</p>



<pre class="wp-block-preformatted">Var d2 As New PDFDocument(template)</pre>



<p>And this is how it will look-like if we decide to save (and open) it:</p>



<pre class="wp-block-preformatted">Var f2 as FolderItem = SpecialFolder.Desktop.Child("SamplePDFFromTemplate.pdf")
d2.save(f2)
f2.Open</pre>



<div class="wp-block-image is-style-default"><figure class="aligncenter"><img loading="lazy" decoding="async" width="220" height="300" src="https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-20.13.30-220x300.png" alt="" class="wp-image-9477" srcset="https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-20.13.30-220x300.png 220w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-20.13.30-751x1024.png 751w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-20.13.30-768x1047.png 768w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-20.13.30-1127x1536.png 1127w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-20.13.30.png 1486w" sizes="auto, (max-width: 220px) 100vw, 220px" /></figure></div>



<p>Not very surprisingly, we get the same PDF contents. After all, we created it from a …&nbsp;well …&nbsp;template.</p>



<p>The main point here is that we can continue working with the <code>d2</code> instance, adding new stuff to it if we want to. Let&#8217;s change that second snippet of code a bit:</p>



<pre class="wp-block-preformatted">Var template As JSONItem = d.Template

Var d2 As New PDFDocument(template)
Var g2 As Graphics = d2.Graphics
g2.DrawText "Hi From The Template!", 50, 160</pre>



<div class="wp-block-image is-style-default"><figure class="aligncenter"><img loading="lazy" decoding="async" width="300" height="227" src="https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-20.17.40-300x227.png" alt="" class="wp-image-9476" srcset="https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-20.17.40-300x227.png 300w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-20.17.40-1024x776.png 1024w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-20.17.40-768x582.png 768w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-20.17.40-1536x1164.png 1536w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-19-a-las-20.17.40-2048x1552.png 2048w" sizes="auto, (max-width: 300px) 100vw, 300px" /></figure></div>



<p>Some interesting things happen here. First of all, you didn&#8217;t need to set the font size because it is using the last <code>FontSize</code> value set in the original document where we got the Template data. That&#8217;s the same as the color used in drawing the text on the new <code>PDFDocument</code> instance- it is using the last <code>DrawingColor</code> set in the original document.</p>



<p>So, from this point on we can add anything we want to to our new <code>PDFDocument</code> created from the template! You may think about having the first snippet of code in one &#8220;main&#8221; app (the one we used to create the original PDF document plus the template data), and the second snippet of code only executed by your &#8220;client&#8221; apps (the one creating a second PDFDocument instance from the Template data).</p>



<p>Learn more about PDFDocument in the <a href="https://documentation.xojo.com/api/pdf/pdfdocument.html">Xojo Documentation</a>.</p>



<p><em>Paul learned to program in BASIC at age 13 and has programmed in more languages than he remembers, with Xojo being an obvious favorite. When not working on Xojo, you can find him talking about retrocomputing at <a href="https://goto10.substack.com" target="_blank" rel="noreferrer noopener">Goto 10</a> and </em>on Mastodon @lefebvre@hachyderm.io.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>PDFDocument: Adding A Table Of Contents</title>
		<link>https://blog.xojo.com/2021/11/18/pdfdocument-adding-a-table-of-contents/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Thu, 18 Nov 2021 12:00:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Multi-Platform Development]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Xojo API 2.0]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=9487</guid>

					<description><![CDATA[Since its first appearance in Xojo 2020r1, one of the most demanded features for PDFDocument has been the ability to add Table Of Content entries.&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Since its first appearance in Xojo 2020r1, one of the most demanded features for <code>PDFDocument</code> has been the ability to add Table Of Content entries. With Xojo 2021r3 that&#8217;s now possible, and pretty straightforward! Continue reading and I will show you how.</p>



<span id="more-9487"></span>



<p>When we think about Table Of Content (TOC) entries, they can clearly be seen as a tree hierarchy where each branch denotes a deeper level hanging from a parent node. </p>



<div class="wp-block-image is-style-default"><figure class="aligncenter"><img loading="lazy" decoding="async" width="476" height="444" src="https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-20-a-las-6.37.56.png" alt="" class="wp-image-9488" srcset="https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-20-a-las-6.37.56.png 476w, https://blog.xojo.com/wp-content/uploads/2021/10/Captura-de-pantalla-2021-10-20-a-las-6.37.56-300x280.png 300w" sizes="auto, (max-width: 476px) 100vw, 476px" /></figure></div>



<p>In the above image, see how the &#8220;First Page&#8221; and &#8220;Second Page&#8221; entries in the TOC are at a root level for the first page and second pages in the document, respectively; while both &#8220;First Section&#8221; and &#8220;Second Section&#8221; are one level deeper, hanging from the root entry, and &#8220;First Sub-Section&#8221; is a third level deeper, hanging in this case from the &#8220;First Section&#8221; entry on the &#8220;First Page&#8221;.</p>



<p>How can we create this kind of TOC hierarchy in a PDFDocument? Using the <code>PDFTOCEntry</code> class in combination with the <code>PDFDocument.AddTOCEntry</code> method.</p>



<p>The <code>PDFTOCEntry</code> Constructor takes a total of four parameters:</p>



<ul class="wp-block-list"><li><strong>PageNumber As Integer</strong>. This is the page number of the <code>PDFDocument</code> instance that will be associated with the TOC entry. PDF pages start at 1.</li><li><strong>Title As String</strong>. The text that will be displayed as the title for the TOC entry in the PDF viewer.</li><li><strong>X As Integer</strong>. The X coordinate where the PDF viewer will jump in the associated page when the user clicks the TOC entry in the PDF viewer.</li><li><strong>Y As Integer</strong>. The Y coordinate where the PDF viewer will jump in the associated page when the user clicks the TOC entry in the PDF Viewer.</li></ul>



<p>We will return a bit later to see how the &#8220;jump&#8221; to the X and Y coordinates behave in the PDF Viewer.</p>



<p>So, in order to create our first root TOC entry for the first page in a PDFDocument instance, all we need to do is:</p>



<pre class="wp-block-preformatted">Var te As New PDFTOCEntry(1,"First Page",0,40)</pre>



<p>Now, the &#8220;First Section&#8221; entry means that we want to add a Bookmark (or TOC entry) to the PDFDocument that, once the user clicks on it, will jump to a specific point (X/Y coordinates) in the same page; so we can create a new instance for it:</p>



<pre class="wp-block-preformatted">Var te1 As New PDFTOCEntry(1,"First Section",100,100)</pre>



<p>And the same thing for the first sub-section that will hang from the &#8220;First Section&#8221; entry:</p>



<pre class="wp-block-preformatted">Var te1a As New PDFTOCEntry(1,"First Sub-Section", 0, 100)</pre>



<p>So far, we have three <code>PDFTOCEntry</code> instances, but we still haven&#8217;t set any hierarchy among these. For that, use the <code>PDFTOCEntry.AddEntry</code> method. The following line of code will add the <code>te1a</code> instance as a sub-node on the <code>te1</code> instance (that is, &#8220;First Sub-Section&#8221; as a node of &#8220;First Section&#8221;):</p>



<pre class="wp-block-preformatted">te1.AddEntry te1a</pre>



<p>And now we can add the <code>te1</code> instance as a sub-node of the <code>te</code> instance (that is &#8220;First Section&#8221; will be a sub-node of &#8220;First Page&#8221;):</p>



<pre class="wp-block-preformatted">te.AddEntry te1</pre>



<p>Thus, in order to add a new section named &#8220;Second Section&#8221; also as a sub-node for the &#8220;First Page&#8221; root node, we only need to type the following lines of code:</p>



<pre class="wp-block-preformatted">Var te2 As New PDFTOCEntry(1,"Second Section", 30,30)
te.AddEntry te2</pre>



<p>You get the idea. I&#8217;m pretty sure you&#8217;ll know by now how to create the required instances and the associated hierarchy for the &#8220;Second Page&#8221; and &#8220;First Section&#8221; entries for the second page of the PDFDocument:</p>



<pre class="wp-block-preformatted">Var teG2 As New PDFTOCEntry(2,"Second Page",0,40)
Var teg2a As New PDFTOCEntry(2, "First Section", 100, 100)

teG2.AddEntry teG2a</pre>



<p>Lastly, all we need to do is add the root instances of the TOC hierarchy (that is <code>te</code> and <code>teG2</code>) to the PDFDocument instance itself. So, let&#8217;s guess that our PDFDocument instance is pointed by the <code>d</code> variable. In that case, these two lines of code will complete the Job:</p>



<pre class="wp-block-preformatted">d.AddTOCEntry te
d.AddTOCEntry teG2</pre>



<h3 class="wp-block-heading">TOC entries and PDF Viewer Behavior</h3>



<p>PDF Viewer apps have their own rules about how or when to &#8220;jump&#8221; to the X / Y coordinates associated with the TOC entries. In brief:</p>



<ul class="wp-block-list"><li>If the target coordinates for the target page are already in the view area, then you won&#8217;t notice anything. After all you are already seeying the contents of the page that the X / Y coordinates are pointing to! For example, this may be the case when you set the PDF Viewer app to display the two pages of the PDF document at once in the view.</li><li>If the target coordinates for the target page are out of the view area, then the PDF viewer will jump to the specified coordinates putting its contents in the view. The behavior in this case depends on the zoom factor you may be using for displaying the page. That is, it is possible you can see the how the PDF viewer &#8220;jumps&#8221; to the second page when you click on the &#8220;Second Page&#8221; entry in the TOC, putting its contents in the view area, but not if you click on the &#8220;First Section&#8221; or &#8220;First Sub-Section&#8221; entries for the first page in the document if that page is already in the view area and the zoom is set to &#8220;Fit Contents to Window&#8221;.</li></ul>



<h3 class="wp-block-heading">Summary</h3>



<p>As we have seen, it is quite simple to create a Table of Contents index for your Xojo PDF documents, adding as many entries as the structure of your PDFs need, in order to provide a better document navigation! Read more about PDFDocument in the <a href="https://documentation.xojo.com/api/pdf/pdfdocument.html">Xojo Documentation</a>.</p>



<p><em>Paul learned to program in BASIC at age 13 and has programmed in more languages than he remembers, with Xojo being an obvious favorite. When not working on Xojo, you can find him talking about retrocomputing at <a href="https://goto10.substack.com" target="_blank" rel="noreferrer noopener">Goto 10</a> and </em>on Mastodon @lefebvre@hachyderm.io.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
