Category Archives: Uncategorized

Generating a PDF Inside of a PhoneGap App

A while back, I was asked if it’s possible to generate PDF documents inside of PhoneGap apps… The answer is definitely yes, and it’s not that hard at all!  I used the JSPDF library, which has a comprehensive JavaScript API for generating PDF documents.

Here’s a quick and easy sample…

First, create a new PhoneGap project using the command line tools, and add the console output and file writer plugins:

phonegap create . "jspdf.sample" "JSPDF App"
phonegap local plugin add org.apache.cordova.file
phonegap local plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-console.git

Next, download the JSPDF project code, and copy the jspdf library from the “dist” directory into your PhoneGap project.  I put it into the www/js directory.  Then, be sure to include the library inside of your main HTML file.

<script type="text/javascript" src="js/jspdf.source.js"></script>

I used the uncompressed/minified source file in the “dist” directory.

Now, let’s generate a PDF document.  Here’s a code snippet that will generate a very simple PDF document and save it to the local file system on the device using PhoneGap’s File API.  This must be called *AFTER* the deviceready event.  All of the console.log statements are just used for debugging this snippet:

//FIRST GENERATE THE PDF DOCUMENT
console.log("generating pdf...");
var doc = new jsPDF();

doc.text(20, 20, 'HELLO!');

doc.setFont("courier");
doc.setFontType("normal");
doc.text(20, 30, 'This is a PDF document generated using JSPDF.');
doc.text(20, 50, 'YES, Inside of PhoneGap!');

var pdfOutput = doc.output();
console.log( pdfOutput );

//NEXT SAVE IT TO THE DEVICE'S LOCAL FILE SYSTEM
console.log("file system...");
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSystem) {

   console.log(fileSystem.name);
   console.log(fileSystem.root.name);
   console.log(fileSystem.root.fullPath);

   fileSystem.root.getFile("test.pdf", {create: true}, function(entry) {
      var fileEntry = entry;
      console.log(entry);

      entry.createWriter(function(writer) {
         writer.onwrite = function(evt) {
         console.log("write success");
      };

      console.log("writing to file");
         writer.write( pdfOutput );
      }, function(error) {
         console.log(error);
      });

   }, function(error){
      console.log(error);
   });
},
function(event){
 console.log( evt.target.error.code );
});

Notice that the PDF generation is actually the easy part.  Once you have created the document, you can get a string representation of the document using the doc.output() function, and with that you can do whatever you want with it.  You can save it to the local file system like I did, send it to a server, or even send it to a native PDF reader on the device.

Be sure to check out the JSPDF open source project on GitHub and review the docs and online examples for more details.

You can download the sample PDF here that was generated from this code snippet.

Color Key/Green Screen Video Techniques with Creative Cloud

In my last post, I talked about masks in After Effects, specifically the new motion tracking feature for rigid masks. In this post, I’m again focusing on video composition, but instead of compositing using masks, I’m going to talk about keying.

Keying is a technique for selectively removing areas of a video based on content inside of that video, so that there is transparency.  With this transparency, you can add layers and special effects to your video compositions.  There is color keying, which removes pixels with specific colors from a video, luminance keying (luma key), which removes pixels based on brightness value, track matte key, and more…  all of which are just different methods of removing pixels from a video and adding transparency.

If you’ve ever wondered how news programs get the weather person to appear in front of an animated weather map, they’re just using color keying/green screen techniques. This is when the subject (the weather person) is captured on a green background, and the green background is removed using color keying.  Then you’re just left with the weather person, which can easily be composited/overlaid on top of the weather map.

Check out the video below to see two examples of keying in action (scroll down to jump directly to the video)… The first example shows how to use a green screen/color key technique in Adobe Premiere to overlay a subject on a background video.

greenscreen

Attribution: Dog Video, Beach Video - You’ll get better results with higher quality video – I just used these for simplicity. The dog video is licensed under Creative Commons with attribution, and the beach video is a preview file from Pond5.

The second example shows usage of color keying to overlay an explosion over a more complicated scene in After Effects – complete with motion tracking, and additional masking to make the explosion look like smoke is billowing down the streets between the buildings.

composition

Now, check out the full video to see how to apply these techniques. You already have have everything you need for these within Creative Cloud.

Here are the techniques that I used in these samples:

If you aren’t already a member of Creative Cloud, learn more and join now at creative.adobe.com.

Enjoy!

Adobe’s MAX Announcements – A Major Update To Creative Cloud

Yesterday kicked off Adobe MAX, Adobe’s annual conference for designers and developers to converge and learn about the latest and greatest from Adobe and our community. In yesterday’s keynote, there were lots of big announcements. If you weren’t able to catch the keynote live, it will soon be available for viewing online. In the meantime, I’ve tried to summarize some of the biggest announcements, so let’s get started…

Major Update to Creative Cloud

Basically, just about everything in the keynote is related to the major updates for Creative Cloud. This includes the vision and direction of Creative Cloud, and all of the tools and services that you are able to take advantage of with your Creative Cloud membership.

First and foremost, Adobe is shifting emphasis from packaged software releases to focusing on the Creative Cloud. From the press release:

Adobe also announced that the company will focus creative software development efforts on its Creative Cloud offering moving forward.  While Adobe Creative Suite® 6 products will continue to be supported and available for purchase, the company has no plans for future releases of Creative Suite or other CS products. Focusing development on Creative Cloud will not only accelerate the rate at which Adobe can innovate but also broaden the type of innovation the company can offer the creative community.

The shift to Creative Cloud is great for more reasons than I could possibly list in one post. To start:

  1. Creative Cloud membership gives you the latest and greatest updates from Adobe, without an upgrade cost, and without having to wait for a boxed release cycle. As soon as updates to the tools are ready, you receive them.
  2. Creative Cloud gives you the ability to have your content everywhere. Not only do you get a shared file space in the cloud that automatically synchs across your computers (complete with private folders and versioning), but you can also have creative applications on multiple computers, you can access your files on Creative Cloud from any device (including your phones and/or tablets), and your application settings can be synched with the cloud.
  3. Creative Cloud membership makes it easy to share your work. You can share your work with the public (either through Creative Cloud sharing, or through Behance integration).

I strongly suggest reading more about Creative Cloud update here, and learning about the vision for Creative Cloud. There is a lot of rumor and misinformation also floating around, so please, please, please read 5 Myths About Creative Cloud, and be sure to check the FAQ if you have any additional questions. Or, just watch the video below, where fellow Adobe evangelist Paul Trani debunks myths about Creative Cloud:

Contrary to FUD that is floating around the Internet, Creative Cloud is not about anti-piracy, it is not about price gouging, it is not about trying to control you. Creative Cloud is about providing you with the best tools and services to produce creative experiences, collaboration, and adding value to your workflow.

For an external (non-Adobe) viewpoint, check out what others have had to say:

I’ll cover more product specific updates in Creative Cloud tools later in this post, but check out the “new features” details to get an idea of what is now available. Or check out fellow evangelist Terry White’s videos on “What’s New In Photoshop CC, Illustrator CC, InDesign CC and Muse CC“.

Improved Desktop Presence

In addition to product updates, the Creative Cloud update also features an improved desktop presence for managing your tools and files.

Creative-Cloud-Feature-Reveal-FINAL-12

From the Creative Cloud team blog, this desktop update will allow you to:

  • Manage your files and sync them to the Cloud
  • Install and update your desktop software
  • Install and manage your Typekit desktop fonts
  • Keep track of everything in your creative work, from Behance notifications, to collaboration invitations, and even updates to your CC apps — all in a single activity stream.

Behance Integration

It’s now easier than ever to showcase your work and gather feedback. You can now publish to Behance directly from within Creative Cloud. You can learn more about Creative Cloud and Behance community integration on adobe.com, but here’s a sampling:

  • Share a work in progress from your Creative Cloud files or within Adobe® Photoshop® and get immediate feedback from the creative community.
  • As you perfect your work, upload new versions to Behance. The community can follow the evolution of your project and post comments along the way.
  • Broadcast your work on Twitter, LinkedIn, and Facebook from within your Creative Cloud tools, all powered by Behance. All in just a few clicks.
  • Creative Cloud keeps track of who’s following you, who appreciates your work, what’s happening with the creatives you’re following, and more — all in a single activity stream.

Creative Cloud membership also comes with the pro features of Behance, including ProSite:

ProSite — a fully customizable professional portfolio with your own unique URL. And with Creative Cloud integration, keeping your portfolio up to date simply becomes part of your usual workflow.

TypeKit Fonts on the Desktop

As part of your Creative Cloud membership, you get access to 175 TypeKit fonts, which can be easily installed through the Creative Cloud desktop application, and are available to your entire desktop. If you were to license each of these fonts individually, it would cost you roughly $25,000. With Creative Cloud membership, you get these with no additional cost. You can read more about TypeKit and desktop font synching on the typekit blog, and see a preview of it in action in the video below:

Product Updates

There are hundreds of new or updated features to Adobe’s desktop applications and services with the latest Creative Cloud update. Here are just a few highlights from the Creative Cloud Team Blog:

  • Camera Shake Reduction in Photoshop CC “deblurs” an image by restoring sharpness to images blurred by camera shake
  • ACR8 is now available as a filter in Photoshop CC; you can apply Adobe Camera Raw processing to any of the layers in your document
  • Touch Type tool in Illustrator CC allows you to design with type in a powerful new way by manipulating characters like individual objects. You can also use multitouch devices as well as a mouse or stylus
  • CSS Designer in Dreamweaver CC provides the most up-to-date CSS and properties available via an intuitive visual editing tool
  • Editing Finesse in Premiere Pro CC focuses on sleek design and customization capabilities, combined with new editing features and keyboard-driven editing improvements
  • Live 3D Pipeline with Cinema4D in After Effects CC lets you add 3D objects to scenes and eliminate intermediate rendering between applications
  • Parallax Scrolling in Muse CC allows you to create stunning effects with just a few mouse clicks—images and elements move in different directions at different speeds when scrolling
  • Motion Paths in Edge Animate allows you to animate elements along totally customizable paths
  • A completely modernized architecture in InDesign and Flash Pro has been rebuilt from the ground up to be faster and more reliable, with a streamlined UI
  • InDesign has a great new QR code creator
  • Flash Pro has real-time drawing and live preview

Check out the links below to see all of the new features for each one of the Creative Cloud tools that will be available in June (there are too many for me to list individually on this post):

In addition to Creative Cloud tools, there have also been updates to the Edge Tools and Services. Adobe Edge Web Fonts has an updated interface on online presence available now, and other Edge Tools have updates that will arrive in June. You can read more about these tools below:

And there have been updates to Adobe’s touch apps:

Creative Cloud

You can always stay on top of the latest updates to Creative Cloud on the Creative Cloud Team blog. If you’re not already a member of Creative Cloud, you really should check it out at creative.adobe.com

Scrolling Large Blocks of Text with Flex for Mobile

I was recently asked by a friend and former colleague about the best way to get text within a s:Label to behave and scroll properly, especially in the Flex mobile SDK. In particular, having a large block of text wrap correctly and scroll only in the vertical direction. By default if you don’t set a size on the label, the behavior of the Flex framework is that the views containing the label will resize, and the text will be displayed as entered (without word wrap or truncation). This may cause some layout issues and confusion as to “what the heck is going on with my text”.

I’ve found that the best way to achieve the desired behavior is to set a maxWidth on the label to force proper word wrapping, and then wrap the label in a s:Scroller to have it scroll properly. I chose to set a maxWidth to allow the label to determine it’s own size, and only to wrap if it needs to. An easy shortcut for proper wrapping is to bind the maxWidth of the label to the width of the scroller component. Also, DO NOT set a static height or a max height. This will cause the text within the label to be truncated, and it will not scroll at all if the static height is less than the height of the scroller. I’ve also noticed that setting cacheAsBitmap=true on the label also helps scroll performance in some circumstances, but this is not required.

Check out a video showing the scroll behavior of a large text block using this approach:

Below is the code that makes it work, which follows the method described above:

<s:Scroller height="100%" width="100%" id="scroller1"> 
	<s:Group> 
		<s:Label id="labelInstance"
				 cacheAsBitmap="true"
				 maxWidth="{ scroller1.width }"
				 color="#FF0000" fontSize="32">
			<s:text>Bacon ipsum dolor sit amet sint cow irure et magna, meatball aliquip qui. Tempor turkey capicola, eiusmod sed nisi dolore. Pig nisi rump boudin in culpa chuck. In ex sausage filet mignon shankle ut. Flank ball tip cillum aute. Nulla frankfurter culpa, elit et esse aute pork salami. Laborum mollit short ribs, in meatloaf eu irure dolor consectetur elit strip steak.
				
				{note: text has been truncated to emphasize actual code, not the random text}
			</s:text>
		</s:Label>
	</s:Group> 
</s:Scroller>

This post is also “powered by bacon”… yes, bacon.

Mobile (3G) vs. WIFI Network Detection with Adobe AIR

Did you know that you can determine whether your mobile device is on wifi or your mobile data connection when using Adobe AIR for mobile? To be honest, I wasn’t aware of it either until yesterday when my friend and former colleague Brian O’Connor pointed me towards a recent tweet from @adobe_cookbook that showed an example how to do it.

These networking APIs have been around since AIR 2.0, but I’ve seldom had the need to dig into them for the desktop. Now that AIR for mobile is widely available, this can be critically important for your applications. For example, what if you want to minimize network usage while on the mobile network? This may even prevent you being chastised for eating up expensive mobile bandwidth.

Using the NetworkInfo class’ findInterfaces() method, you can retrieve a list of all network interfaces on your computer/device. If you iterate through these, you can see which are active, what their IP and MAC addresses are, and even which IP protocol version they are using. Here’s a quick example (code below the video):

Network Detection on AIR Mobile

I know that video is a little hard to see, so here are some screen captures. First, a capture showing the mobile network connection active:

Mobile Network Active

Next, a capture showing the WIFI network active:

WIFI Network Active

Basically, I just have a list that shows all of the network interfaces. When the app loads, or whenever the network connection changes, the content of that list is updated to reflect the current state of the network interfaces. If you want to determine whether you are on wifi, you can compare the name of the active network interface to see if it contains the string “wifi”, as shown in the Adobe Cookbook.

<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009" 
		xmlns:s="library://ns.adobe.com/flex/spark" 
		title="Network Detection"
		creationComplete="view1_creationCompleteHandler(event)">
	
	<fx:Script>
		<![CDATA[
			import mx.collections.ArrayCollection;
			import mx.events.FlexEvent;
			
			[Bindable]
			private var interfaces : ArrayCollection = new ArrayCollection();
			
			protected function view1_creationCompleteHandler(event:FlexEvent):void
			{
				NativeApplication.nativeApplication.addEventListener(Event.NETWORK_CHANGE, onNetworkChange);
				updateInterfaceDataProvider();
			}
			
			protected function onNetworkChange(event : Event) : void
			{
				updateInterfaceDataProvider();
			}
			
			//this is used b/c you can't bind directly to a Vector
			protected function updateInterfaceDataProvider() : void
			{
				interfaces.disableAutoUpdate();
				interfaces.removeAll();
				
				for each ( var ni : NetworkInterface in NetworkInfo.networkInfo.findInterfaces() )
				{
					interfaces.addItem( ni );
				}
				interfaces.enableAutoUpdate();
			}
		]]>
	</fx:Script>
	
	<s:List dataProvider="{ interfaces }" 
			width="100%" height="100%"
			itemRenderer="NetworkInterfaceDetailsRenderer"/>
</s:View>

In the list renderer, I’m simply setting an iconFunction and messageFunction to reflect the details on each individual NetworkInterface.

<?xml version="1.0" encoding="utf-8"?>
<s:IconItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
					xmlns:s="library://ns.adobe.com/flex/spark"  
					labelField="name" 
					messageFunction="networkInterfaceDetail" 
					iconFunction="networkInterfaceIcon"
					iconWidth="64" iconHeight="64" >
	
	<fx:Script>
		<![CDATA[
			
			[Embed(source="assets/active.png")]
			public static var activeImageClass:Class;
			
			[Embed(source="assets/inactive.png")]
			public static var inactiveImageClass:Class;
			
			private function networkInterfaceDetail(item:Object):String
			{
				var ni : NetworkInterface = this.data as NetworkInterface;
				if ( ni )
				{
					var result : String = "mac: " + ni.hardwareAddress;
					for each ( var ia : InterfaceAddress in ni.addresses )
					{
						result += "\nip: " + ia.address + " " + ia.ipVersion;
					}
					result += "\nmtu: " + ni.mtu.toString();
					return result;
				}
				
				return "Error: Unable to identify network interface.";
			}
			
			private function networkInterfaceIcon(item:Object):Object
			{
				var ni : NetworkInterface = this.data as NetworkInterface;
				if ( ni && ni.active )
					return activeImageClass;
				return inactiveImageClass;
			}
		]]>
	</fx:Script>
</s:IconItemRenderer>

One thing not to forget: You must make sure that your application has been provisioned to allow access to network interfaces! You’ll just need to uncomment the Android permissions in your app.xml for network state:

			    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
			    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>