TweetFollow Us on Twitter

Dynamic PDF

Volume Number: 16 (2000)
Issue Number: 3
Column Tag: Programming Techniques

Dynamic PDF Made Easy

by Kas Thomas

It's simpler than you think to generate custom PDF documents in real time using Perl and CGI

Adobe's Portable Document Format (PDF) has won universal acclaim as document interchange format, because of its ability to deliver graphically rich, structured content consistently across multiple operating environments. Because of its strong support for vector graphics, font embedding, hypertext links, and other advanced features, PDF is a powerful, far-reaching document standard. But that also makes it a relatively complex standard. (For details, see the September 1999 MacTech.) PDF's complexity, in turn, has discouraged many web developers from attempting to write PDF files dynamically, at the server. Automatically generated HTML pages are common; but when was the last time you saw an auto-generated PDF web page?

It turns out that with a little foreknowledge of PDF's internal workings, and a good grasp of CGI fundamentals, it's not that hard to put together server scripts that will generate PDF on demand. There's no question that dynamic PDF can be a challenge to do right. But if your dynamic document needs are modest (for example, if you'd simply like to be able to generate a custom "Thank You" page at run time) and your Perl skills are passable (i.e., you've graduated from writing "Hello World" to generating the much more impressive string "Internal Server Error"), you can automate the serving of custom PDF pages with surprisingly little effort. In fact, a Perl script comprising no more than five or six dozen lines of code will get you started.

Our Strategy

Our strategy will be simple: We want to be able to collect an arbitrary glob of "user text" from a web form, and convert that text to a PDF page served back to the user via HTTP, suitable for viewing in a browser equipped with the free Acrobat Viewer plug-in. For simplicity's sake, we'll start by omitting any attempts at vector graphics, colored text, rotated text, styled text in various point sizes, etc. (But I hasten to add that before this article is finished, we're going to be doing all of those things and more.) For starters, we just want to serve the user's words back to him, at any convenient point size, in black and white, on a letter-sized PDF page. For sake of convenience, we're also going to generate the "data collection" form and our PDF reply from one and the same Perl script. That way, we don't have to keep track of multiple documents: an HTML form, Perl scripts, CSS stylesheets, etc. If you want to add that complexity to the picture yourself later, so be it. Here, we're going to keep things stone-simple.

I might point out that "live" copies of the dynamic-PDF scripts developed below can be found at (which is a portal page with links to several working scripts).

I also want to stress that when we're done, the PDF pages we will have generated can be saved to disk using your browser's Save As feature. (Reader won't save the docs, but your browser will.) Thus, we will have achieved the Holy Grail of the PDF world: writing PDF without using Distiller or Acrobat.

Once we've gotten our basic approach nailed down, we'll branch out into fancy features like colored backgrounds, stroked/filled paths, rotated text, styled text, etc. But first, a detour into the land of PDF internal structure.

PDF at the Subatomic Level

Internally, a PDF file consists of plain-ASCII object descriptions, following a notably Postscript-like (i.e., postfix-notation) syntax. All PDF files have a header (containing version information), a cross-reference (or 'xref') table containing offsets to the various objects that make up the file, and a trailer containing references to the root object as well as the byte offset from the start of the file to the beginning of the 'xref' table. (See my story in see the September 1999 MacTech for more information.) The formal PDF specification, available online at, describes the relationships between PDF objects (and the meanings of various dictionary "key" entries) in comprehensive detail, if you're interested. But we're going to skip all that, because most of it is not necessary for what we're doing.

It turns out you can bend (or even break) a lot of the "rules" spelled out in the PDF spec, without making Acrobat Reader unhappy, if you know a thing or two about PDF internals. An instructive exercise in this regard is to make Adobe's Distiller program generate a small "Hello World" type of file, then examine the file in a text editor-and try to find superfluous data in it that can be removed. If you try this, you will quickly discover that /Info objects, for example, contain meta-data about the PDF file (such as the doc's author, subject, producer, keywords, etc.) that can easily be dispensed with. Likewise, Adobe tends to insert long /ID objects (containing a kind of "digital fingerprint" for identification of the file) in PDF files; these aren't strictly needed.

If you keep removing superfluous objects and data items from a PDF file, you may be amazed at how much "data" you can actually get rid of without making Reader complain. A careful re-reading of the PDF Specification usually reveals that items you thought were mandatory are actually optional. Even the all-important 'xref' table isn't strictly needed, since Acrobat Reader can (and will, and does) generate the necessary byte offsets itself, at runtime, if the table is defective or missing.

In late 1999, I sponsored a contest at <> in which the goal was to produce the smallest possible PDF file that wrote "Hello World" to the screen without making Acrobat Reader generate any error dialogs. Amazingly, the winner of that contest submitted a file that was only a little more than 200 bytes long:

1 0 obj<</Pages 2 0 R>>
2 0 obj<</Kids[<</Parent 2 0
BT/R 14
Tf(Hello World!)Tj
trailer<</Root 1 0 R>>

Note that the second object (starting with "2 0 obj...") is extra-long, with many nested "dictionary" entries, ending only just before the word "trailer" at the bottom of the file. This particular PDF file uses 14-point Arial as the typeface. No font encodings are embedded in the file, however, because Arial is one of the base-14 fonts that Acrobat Reader ships with. (Arial replaced Helvetica in the version-4.0 release of Reader.) Every machine that has Acrobat Reader is guaranteed to have Arial.

There are many things technically "wrong" with this short PDF file, including the fact that it has no 'xref' table and contains a text stream that is opened with 'BT' (for Begin Text) but is never closed with 'ET' (End Text). In many ways, it's a wonder Reader can even parse and display this file. Yet it does.

There is one small technical difficulty with this file that impacts viewing: Namely, no positioning information is given for the text - which means (since Reader "zeroes out" the current transformation matrix, or CTM, before displaying any block of text) that the starting "pen position" for displaying "Hello World!" in this instance is the origin of user space: i.e., the lower left corner of the page. You have to scroll down to the very bottom of the page to see the single line of text. To fix this requires that we add a transformation matrix of our own to the text stream:

1 0 obj<</Pages 2 0 R>>
2 0 obj<</Kids[<</Parent 2 0
BT/R 14
1 0 0 1 72 720 Tm
Tf(Hello World!)Tj
trailer<</Root 1 0 R>>

Can you spot the change? We've added a line that ends with 'Tm' (the transform-matrix operator). The six-number matrix will look familiar to you if you've studied Postscript. The first four numbers are scaling and skewing factors (signifying no change in those characteristics, in this case); the final two numbers are translation values in 'x' and 'y', respectively. Since the default user space in PDF has 72 units to the inch, using values of 72 and 720 result in the starting position for our text results in our text being drawn one inch from the left edge of the page and ten inches up from the bottom. (In PDF, 'y' units get bigger as you go up.) Now our 14-point text will be drawn where the user can see it.

In the Perl script that follows, we're going to use a variation of the foregoing PDF file as the basis (the "template," if you will) for our dynamically generated PDF page. While some experts may cringe at the thought of using a "broken" PDF file as the starting point for this kind of exercise, the fact is that for illustrative purposes, a "subatomic" template file of this kind is hard to beat. Besides, the proof of the pudding is that Acrobat Reader doesn't in any way "choke" on the end result. What the user sees in his (or her) browser is a fully functional PDF file: one that can be saved to disk (using the browser's Save As feature) for later use.

The Common Gateway

Collecting information from users is a common task in the world of the Web, calling for the use of interactive forms. Sometimes, the form in question is a static HTML file stored on a server; but increasingly, HTML forms themselves are dynamically generated at the server in response to user requests. That is, the form itself doesn't exist until a CGI script, often written in Perl, generates it.

CGI (the Common Gateway Interface) is nothing more than a set of conventions for pushing and pulling information across an HTTP connection. Forms, and the scripts that retrieve information from web forms, use the CGI protocol to get the job done. Learning to write CGI scripts in Perl is an art unto itself, but the job is made tremendously easier if you take advantage of some of the excellent free Perl libraries available for implementing CGI processes.

Arguably the best Perl library for this task is Lincoln Stein's powerful package. This set of routines (which takes the pain out of writing HTML at the server and dealing with web forms) is so useful that it now ships with Perl as part of the "full install" of the language. What this means is that any Unix server that has Perl 5.003, patchlevel 7 or higher (as almost all do) automatically has, waiting to be called from any Perl script.

When you use, you don't have to worry about whether incoming form data is being supplied via GET or POST, where it's being stored on the server, or any of the nasty parsing details involved in extracting urlencoded data from HTTP streams. To get the value of a form field called "UserName" from a Perl script at runtime using, all you have to do is:

$name = param('UserName');

Here, $name refers to the local scalar variable into which we wish to store the value from "UserName." If the user has typed "John Smith" into the relevant form field before Submitting the form data to the server, then $name will contain "John Smith" after this line of code executes. The param() function in takes care of finding the incoming data, decoding it if it's urlencoded, etc.

Dynamic Forms Using

One task excels at is generating HTML code dynamically. For example, to create the HTML form shown in Figure 1, all we have to do is execute the following few lines of Perl:

  print header,
 		start_html(-title=>'PDF Bounceback, by Kas Thomas',
 		p(h2('PDF Text Entry'));

	print start_form,
        submit(-name=>'action',-value=>'Generate PDF');

Figure 1.A form created dynamically using

The function h2('content here') applies an HTML level-2 headline tag around the text "content here"; likewise, p() applies paragraph tags around a block of text, and so forth. Nesting the function calls causes the relevant HTML tags to nest correctly. A common idiom in Perl for getting multiple strings to print to an output stream is to separate the strings with commas and put them between print at the start and a semicolon at the end. Functions like header(), start_form(), and end_form() are part of the package. (In Perl, parentheses after a function name do not constitute a "function call operator." They are therefore optional, if no arguments are given.)

If you write a Perl script containing the foregoing lines of code, name the script "", and place it in the "cgi-bin" directory of your web server, then whenever anybody goes to the script's URL, the script will launch automatically and write the form shown in Figure 1 to the caller's browser. This is how many (if not most) dynamic forms work.

A Dynamic PDF Script

At this point, believe it or not, we're in a position to put together a full, working Perl script for producing an HTML form dynamically, retrieving the contents of that (filled-out) form, and auto-generating a PDF reply back to the user's browser. Listing 1 shows such a script, complete.

Listing 1:

A complete Perl script for generating an HTML form, retrieving the

form's contents, and writing the contents back out as a PDF file.

# ------------------------------
# Script: (simple script to output PDF dynamically)
# © 2000 by Kas Thomas. Updates at
# ------------------------------
use CGI qw/:standard/;

# Check params, and if null, show form...
DrawForm() unless param();

$allText = param('UsersText');
print header("application/pdf");   # output PDF header


foreach $line (split /\n/,$allText) {
	 print '(' . $line . ')Tj';
     print "\n";   
	 print 'T*';				 # goto start of next line		    
     print "\n";   


# - - - - - - - - - - DrawForm() - - - - - - - - - - -
sub DrawForm {

	print header,
 		start_html(-title=>'PDF Bounceback, by Kas Thomas',
 		p(h2(font({-color=>'red'},'PDF Text Entry')));

	print start_form,
        submit(-name=>'action',-value=>'Generate PDF');

# - - - - - - - - - - Send_PDF_Leader() - - - - - - - -
sub Send_PDF_Leader {

print <<PDF_LEADER;
1 0 obj<</Pages 2 0 R>>
2 0 obj<</Kids[<</Parent 2 0 R/Resources<</Font<</R
BT/R 14
1 0 0 1 72 700 Tm
15 TL

# - - - - - - - - - - Send_PDF_Trailer() - - - - - - - -
sub Send_PDF_Trailer {

print <<PDF_TRAILER;
trailer<</Root 1 0 R>>

After a use directive to make sure Perl knows we need to use the package, we check to see whether the function param() returns nothing, in which case it means the script is being called for the first time. If the script is being called for the first time, it means we need to generate the HTML form of Figure 1 - which is accomplished by the subroutine DrawForm(). Otherwise, if param() is not nil, we're responding to a hit on the "Generate PDF" button (which is the form's equivalent of a Submit button).

If we're responding to a hit on the Generate PDF button, the first order of business is to retrieve the user-entered text, which we do with:

$allText = param('UsersText');

The textarea field of the HTML form is named "UsersText"; hence, we want to retrieve whatever the user typed there. The foregoing line of code captures the user's text into a single big string (a scalar variable, in Perl parlance) called $allText. We'll have occasion to parse that big string into smaller constituents (representing individual lines of text) in a moment.

Before we can write PDF to the user's browser, we have to open an HTTP connection and send an HTTP header with the appropriate MIME type for PDF (which is "application/pdf"). This is the browser's way of knowing what kind of file is about to arrive. The browser can take appropriate action in terms of launching helper apps, handing off control to plug-ins, or handling the transaction itself. In this instance, if the user has the Acrobat browser plug-in installed, the browser will hand control to the plug-in. It's also possible that the user has set the browser up such that incoming PDF files are redirected to the standalone Acrobat Reader app. If the MIME type "application/pdf" has not been registered with the browser, the browser will react to the incoming header by asking the user what to do with the about-to-arrive unknown file type. The user can then cancel out of the transaction, store the incoming file to disk, etc.

Opening the HTTP connection and sending the proper header is done with:

print header("application/pdf");

After that, our script goes to a subroutine called Send_PDF_Leader(). This subroutine simply writes 200 bytes or so of raw PDF to the HTTP connection. Most of that code should look familiar to you from our discussion of minimal PDF files earlier.

Writing the User's Text

Next comes our script's "main loop," you might say, in which we parse the user's text into individual lines and write them out as PDF text-stream data. We use Perl's split() function to divide the $allText string into substrings, splitting at every newline. Then we write a line of user text, in parentheses, followed by the 'Tj' operator (PDF's "writeline" operator), and after every line of text so processed, we write a 'T*', which (in PDF) means to drop down to the start of the next line (using the current leading) and prepare the virtual pen to write more text.

After writing every line of user text, we call Send_PDF_Trailer() to write out the last few bytes of our PDF template. At that point, we're finished.

An example of a dynamically generated PDF page using this script is shown in Figure 2.

Figure 2.A dynamically generated PDF file.

The Great Escape

At this point, we have a script that obediently writes our user's text input as 14-point Arial, in black ink on a white PDF page. Not very interesting-looking. It would be nice if we could jazz things up a bit by drawing our text in color, perhaps in various additional sizes. It would also be nice if we could specify something other than a pure white background. But before we proceed to increase the spiff factor of our PDF, we need to attend to one small detail.

PDF represents strings internally as ASCII character sequences inside parentheses. Thus, whenever a string contains parentheses as part of the text, they need to be "escaped" with a preceding backslash. Otherwise, the PDF interpreter, upon encountering a right-parenthesis inside a block of text, may think the text string has been terminated! The right-paren will be treated as an end-of-string marker. This could lead to strange errors if our user is in the habit (as many of us are) of loading up text with parenthetical remarks.

Fortunately, it's not hard to trap parens and "escape them" automatically for the user. Of course, we also have to trap and escape backslashes in the user's text, because (again) PDF treats all backslashes as "special" in a text stream. To deal with parens and backslashes, we declare an associative array in Perl as follows:

%PDF_ESCAPES = ('\\' => '\\\\', 
                ')'  => '\)', 
                '('  => '\(');

The way this special kind of array (sometimes called a hash) works is that when we want to look up the "replacement" for, say, a bare right-paren, we just need to do:

$PDF_ESCAPES { ')' };

Note the dollar sign preceding the hash name (and the curly braces enclosing the array index). In Perl, the dollar sign means we are coercing the array lookup into a scalar context. When the above statement evaluates, it will evaluate to the lookup value '\)' (i.e., the string representing our properly escaped paren).

Of course, Perl (like PDF) also treats backslashes as special, which means that a string representing a literal backslash needs to be escaped - with a backslash! That is, the string '\\' prints as one backslash (not two) in Perl. Likewise, '\\\\' is treated as two literal backslashes in a row, not four. That's why the first lookup item in our hash, namely '\\\\', is associated with '\\'. (Confused yet?)

Now. We need to check every line of user input before writing it as raw PDF, so that any parens or backslashes contained in the user's text get converted to their properly escaped equivalents, preventing Acrobat Reader from choking. We can accomplish this essential check with the following line of code, inserted in our "main loop":

$line =~ s/([\\()])/$PDF_ESCAPES{$1}/ge;

"Wow," you're probably muttering, "what a weird-looking line of code!" And indeed it is. A Perl fan will recognize it immediately as a powerful regex-based substitution (regex being short for "regular expression"). In Perl, a statement like

$myString =~ s/this/that/g;

means to scan the contents of $myString, looking for the substring 'this', and upon finding a match, substitute (per the leading lowercase 's') the string 'that'; and oh, by the way, do this repeatedly (globally) throughout the entire contents of $myString. (That's what the trailing lowercase 'g' means.)

In our somewhat complicated substitution operation, we're scanning for any match of the regular expression [\\()], which is a character class with three members: the backslash character (which we have to escape with a backslash, for Perl's benefit; hence '\\'), the left-paren, and the right-paren. Square brackets mean that these characters form a class of allowable "match" characters. Any match of any one of these characters (in any order) inside the target string will trigger a "hit." Enclosing the entire character class within parentheses, as in ([\\()]), means we want Perl to store a temporary copy of any match that occurs, in a variable called $1. (If you're not familiar with this idiom, don't spend too much time worrying about it right now. You can always read up on regexes later.) Our replacement value, which Perl consults whenever a "hit" happens, in this case is $PDF_ESCAPES{$1} - that is to say, we use the match value ($1) as an index into our associative array, in order to retrieve the appropriate replacement string. This trick will only work, however, if we remember to put a trailing lowercase 'e' on the end of the expression, which means evaluate the replacement string as a Perl expression. Otherwise, Perl will literally substitute whatever's in the replacement position, unevaluated. That's not what we want.

Upping the Spiff Factor

As I started to say before, it would be nice if we could "spiff up" our PDF output a bit, augmenting it with colored text, styled text, or perhaps some vector graphics or different background colors, etc. - anything except plain old black text on a white background.

Adding extra spiff turns out to be astonishingly easy. All we need to do is let the user "drop down" into low-level PDF whenever he or she wants to. Follow me for a minute. Suppose we invent a special "escape command" of our own, signified by (let's say) the ASCII string <@>. We'll call this the "escape-to-PDF" operator. To get back to normal text-writing mode, we'll require the use of </@>, which we'll call the "escape-to-text" operator. Anything bracketed by <@> and </@> gets treated as raw PDF. While your user is in "raw PDF" mode, he can make use of any of the Postscript-like page operators and vector-drawing commands recognized by the PDF Specification: m for moveto, l for lineto, rg for setting the RGB color, Tm for set matrix, B for fill and stroke path, etc. (See the URL given earlier for the formal PDF Specification, at Adobe's web site.)

Using the same regex-based substitution trick that we used before, we can add one more lookup table (or associative array) to our script, and add one more regex-substitution line to our main loop. Only this time, the hash will return a value of ')Tj ' for any hit on <@>, and a value of ' (' for any hit on </@>. That way, whenever the user types <@> as part of his text stream, our script outputs a PDF end-of-string marker, followed by the PDF "write line" operator (Tj), spoofing Acrobat Reader into letting the user write raw page operators, if he wants to. When the user types </@>, the script outputs a "begin string" marker, and Reader is spoofed into going back into text-stream mode.

What Can You Do With It?

Now we've got quite a bit of power in our hands. If you know a little bit of PDF, you can create almost any kind of display magic you want with your dynamically generated PDF document. Let's try the following code entered into our form's main text area:

<@>0.85 0.85 0.85 RG</@>
<@>1 J 110 w 250 600 m 250 600 l B</@>
<@>.6 .6 .6 RG</@>
<@>18 w 72 72 m 72 720 l 540 720 l 540 72 l s</@>
<@>0 1 -1 0 144 520 Tm</@>

Let's try some rotated text.

The end result is shown in Figure 3. We've created a PDF document containing a large grey box (going around the edges of the page), a filed grey circle, and the words "Let's try some rotated text" running vertically up the page.

Figure 3.Custom-generated PDF containing rotated text and stroked vector graphics.

To understand what's going on, let's look at the above form input, one line at a time. The first five lines are encapsulated by <@> and </@> , which means we're writing raw PDF. The first line of raw PDF contains 0.85 0.85 0.85 RG, which sets the stroke color (in our default RGB color space) to 15% grey. In PDF, RGB channel values run from zero to 1.0, with 1.0 being brightest. Therefore, setting each channel to 0.85 makes for 15% grey (or 85% white).

The second line is more complicated. Basically, it says to set the default line end-cap style to rounded end-caps (that's what '1 J' means); set the default line width to 110 pixels (thus '110 w'); move the pen to page coordinates of 250,600 ('m' means "moveto"); draw a line to 250,600; and finally, stroke the path ('B'). In plain English: "Draw a zero-length line, 110 pixels wide, at 250,600 with rounded end caps." Since the line has zero length, only the end caps are drawn. In this way, we spoof Acrobat into drawing a perfect circle, which looks filled (although really it's only stroked). This is an old Postscript hack for drawing filled circles. The reason we use it here is that PDF doesn't have a "draw circle" operator, just Bézier-curve operators. (I don't know about you, but I find the idea of drawing a circle using linked Bézier segments too painful to think about.)

Next, in the third line of raw PDF, we set the stroke color to 40% grey (60% white) with .6 .6 .6 RG.

In line four, we change the default stroke width to 18 pixels ('18 w'); move the pen to 72,72; draw a line to 72,720; another line to 540,720; a line to 540,72; and then we use the 's' command, which in PDF means "close this path and stroke it." This is how we produced a thick, dark-grey line going around the margins of the page.

Finally, in the fifth line we perform some matrix magic. Transform matrices, in PDF (as in Postscript) consist of six numbers, the first four of which specify scaling and rotation. To rotate the coordinate system, just make sure the first four numbers represent (consecutively) the cosine, sine, negated sine, and cosine of the desired angle. In our example, we used 90 degrees as the angle (hence the matrix values 0, 1, -1, and 0). The final two numbers in the transform matrix represent translation values in x and y. That is, we move the origin of space to whatever these numbers are (in this case, 144,520). Recall that the origin starts life at the lower left corner of the page.

Now when our text is drawn, it begins at 144,520 but runs at 90 degrees up the page. Since text is (by default) filled but not stroked, it gets drawn in black (the default fill color, which we have not changed).

Simple as pi.


We've covered an incredible amount of ground in a relatively small space. Not only have we shown how to serve dynamic PDF pages from a compact (80 lines or so) Perl script, but we've integrated a low-level "raw PDF" editor into the data-input form such that if the user wants to, he can produce sophisticated graphics effects inside the generated PDF page. (A "live" copy of this script, and others similar to it, can be found online at

Of course, many useful additions could still be made to our little script. A useful exercise would be to add such features as:

  • Additional fonts, and a facility for the user to change font sizes on the fly.
  • Automatic line-wrapping, with or without justification.
  • Custom margin widths.
  • Custom background colors. (This is just a matter of drawing a filled, colored rectangle large enough to cover the entire page.)
  • Stylesheets.

You can probably think of lots of other features that would be nice to have. The good news is, now you're in a position to implement them, because (as you now know) dynamic PDF really isn't that hard.

Kas Thomas ( consults for Adobe Systems and writes a regular column about PDF-related programming (covering JavaScript, CGI, dynamic PDF, and related issues) for He has been programming in C and assembly on the Mac since MC68000 days and remembers when the MacOS ran in black-and-white.


Community Search:
MacTech Search:

Software Updates via MacUpdate

Live Home 3D Pro 3.2.2 - $69.99
Live Home 3D Pro, a successor of Live Interior 3D, is the powerful yet intuitive home design software that lets you build the house of your dreams right on your Mac. It has every feature of Live Home... Read more
FileZilla - Fast and reliable F...
FileZilla (ported from Windows) is a fast and reliable FTP client and server with lots of useful features and an intuitive interface. Version MSW: Add misssing file to .zip binary package... Read more
Spotify - Stream music, crea...
Spotify is a streaming music service that gives you on-demand access to millions of songs. Whether you like driving rock, silky R&B, or grandiose classical music, Spotify's massive catalogue puts... Read more
Sierra Cache Cleaner 11.0.6 - Clear cach...
Sierra Cache Cleaner is an award-winning general purpose tool for macOS X. SCC makes system maintenance simple with an easy point-and-click interface to many macOS X functions. Novice and expert... Read more
DiskCatalogMaker 7.1.2 - Catalog your di...
DiskCatalogMaker is a simple disk management tool which catalogs disks. Simple, light-weight, and fast Finder-like intuitive look and feel Super-fast search algorithm Can compress catalog data for... Read more
Live Home 3D Pro 3.1.2 - $69.99
Live Home 3D Pro, a successor of Live Interior 3D, is the powerful yet intuitive home design software that lets you build the house of your dreams right on your Mac. It has every feature of Live Home... Read more
Deeper 2.2.1 - Enable hidden features in...
Deeper is a personalization utility for macOS which allows you to enable and disable the hidden functions of the Finder, Dock, QuickTime, Safari, iTunes, login window, Spotlight, and many of Apple's... Read more
Pinegrow 3.04 - Mockup and design webpag...
Pinegrow (was Pinegrow Web Designer) is desktop app that lets you mockup and design webpages faster with multi-page editing, CSS and LESS styling, and smart components for Bootstrap, Foundation,... Read more
Deeper 2.2.1 - Enable hidden features in...
Deeper is a personalization utility for macOS which allows you to enable and disable the hidden functions of the Finder, Dock, QuickTime, Safari, iTunes, login window, Spotlight, and many of Apple's... Read more
Spotify - Stream music, crea...
Spotify is a streaming music service that gives you on-demand access to millions of songs. Whether you like driving rock, silky R&B, or grandiose classical music, Spotify's massive catalogue puts... Read more

Latest Forum Discussions

See All

The best deals on the App Store this wee...
There are quite a few truly superb games on sale on the App Store this week. If you haven't played some of these, many of which are true classics, now's the time to jump on the bandwagon. Here are the deals you need to know about. [Read more] | Read more »
Realpolitiks Mobile (Games)
Realpolitiks Mobile 1.0 Device: iOS Universal Category: Games Price: $5.99, Version: 1.0 (iTunes) Description: PLEASE NOTE: The game might not work properly on discontinued 1GB of RAM devices (iPhone 5s, iPhone 6, iPhone 6 Plus, iPad... | Read more »
Layton’s Mystery Journey (Games)
Layton’s Mystery Journey 1.0.0 Device: iOS Universal Category: Games Price: $15.99, Version: 1.0.0 (iTunes) Description: THE MUCH-LOVED LAYTON SERIES IS BACK WITH A 10TH ANNIVERSARY INSTALLMENT! Developed by LEVEL-5, LAYTON’S... | Read more »
Full Throttle Remastered (Games)
Full Throttle Remastered 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: Originally released by LucasArts in 1995, Full Throttle is a classic graphic adventure game from industry legend Tim... | Read more »
Stunning shooter Morphite gets a new tra...
Morphite is officially landing on iOS in September. The game looks like the space shooter we've been needing on mobile, and we're going to see if it fits the bill quite shortly. The game's a collaborative effort between Blowfish Studios, We're Five... | Read more »
Layton's Mystery Journey arrives to...
As you might recall, Layton's Mystery Journey is headed to iOS and Android -- tomorrow! To celebrate the impending launch, Level-5's released a new trailer, complete with an adorable hamster. [Read more] | Read more »
Sidewords (Games)
Sidewords 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: Grab a cup of coffee and relax with Sidewords. Sidewords is part logic puzzle, part word game, all original. No timers. No... | Read more »
Noodlecake Games' 'Leap On!...
Noodlecake Games is always good for some light-hearted arcade fun, and its latest project, Leap On! could carry on that tradition. It's a bit like high stakes tetherball in a way. Your job is to guide a cute little blob around a series of floating... | Read more »
RuneScape goes mobile later this year
Yes, RuneScape still exists. In fact, it's coming to iOS and Android in just a few short months. Jagex, creators of the hit fantasy MMORPG of yesteryear, is releasing RuneScape Mobile and Old School RuneScape for mobile devices, complete with... | Read more »
Crash of Cars wants you to capture the c...
Crash of Cars is going full on medieval in its latest update, introducing castles and all manner of new cars and skins fresh from the Dark Ages. The update introduces a new castle-themed map (complete with catapults) and a gladiator-style battle... | Read more »

Price Scanner via

Save or Share
FotoJet Designer, is a simple but powerful new graphic design apps available on both Mac and Windows. With FotoJet Designer’s 900+ templates, thousands of resources, and powerful editing tools you... Read more
Logo Maker Shop iOS App Lets Businesses Get C...
A newly released app is designed to help business owners to get creative with their branding by designing their own logos. With more than 1,000 editable templates, Logo Maker Shop 1.0 provides the... Read more
Sale! New 15-inch MacBook Pros for up to $150...
Amazon has the new 2017 15″ MacBook Pros on sale for up to $150 off MSRP including free shipping: – 15″ 2.8GHz MacBook Pro Space Gray: $2249 $150 off MSRP – 15″ 2.89Hz MacBook Pro Space Gray: $2779 $... Read more
DEVONthink To Go 2.1.7 For iOS Brings Usabili...
DEVONtechnologies has updated DEVONthink To Go, the iOS companion to DEVONthink for Mac, with enhancements and bug fixes. Version 2.1.7 adds an option to clear the Global Inbox and makes the grid... Read more
15-inch 2.2GHz Retina MacBook Pro, Apple refu...
Apple has Certified Refurbished 2015 15″ 2.2GHz Retina MacBook Pros available for $1699. That’s $300 off MSRP, and it’s the lowest price available for a 15″ MacBook Pro. An Apple one-year warranty is... Read more
13-inch 2.3GHz Silver MacBook Pro on sale for...
B&H Photo has the new 2017 13″ 2.3GHz/256GB Silver MacBook Pro (MPXU2LL/A) on sale for $1399 including free shipping plus NY & NJ sales tax only. Their price is $100 off MSRP. Read more
Apple Tackles Distracted Driving With iOS 11...
One of the most important new features coming in iOS 11 is Do Not Disturb while driving, intended to help drivers stay more focused on the road. With Do Not Disturb while driving, your iPhone can... Read more
iMazing Mini for Mac: Free Automatic and Priv...
Geneva, Switzerland-based indie developer DigiDNA has released iMazing Mini, their free macOS utility designed to automatically back up iOS devices over any local Wi-Fi network. The app offers users... Read more
Clearance 2016 13-inch MacBook Airs, Apple re...
Apple dropped prices recently on Certified Refurbished 2016 13″ MacBook Airs, with models now available starting at $809. An Apple one-year warranty is included with each MacBook, and shipping is... Read more
9.7-inch 2017 iPads available for $299, save...
B&H Photo has 2017 9.7″ 32GB WiFi iPads on sale for $30 off MSRP for a limited time. Shipping is free, and pay sales tax in NY & NJ only: – 32GB iPad WiFi: $299, $30 off Read more

Jobs Board

*Apple* Retail - Multiple Positions - Apple...
SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions - Apple...
SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
Senior Payments Architect - *Apple* Pay - A...
Changing the world is all in a day's work at Apple . If you love innovation, here's your chance to make a career of it. You'll work hard. But the job comes with more Read more
Frameworks Engineering Manager, *Apple* Wat...
Frameworks Engineering Manager, Apple Watch Job Number: 41632321 Santa Clara Valley, California, United States Posted: Jun. 15, 2017 Weekly Hours: 40.00 Job Summary Read more
Manager, *Apple* Media Products - Apple Inc...
Job Summary The Apple Media Products Discovery, Fraud and Abuse team is responsible for protecting the integrity of Apple services. As a manager of the team, you Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.