Home

Generic PDF Reader Detector




Download PluginDetect and DummyPDF here...

In order to do generic pdf detection in a browser, you will need 2 things:

1) download the DummyPDF file (just right click and Save As). The DummyPDF file is used by PluginDetect to do detection in browsers that have a built-in PDF viewer.

2) download the PluginDetect script itself. The PluginDetect script generator will allow you to customize the PluginDetect script to include whatever features you desire.



2 Kinds of PDF Readers: Plugin vs Built-in

Most browsers require a plugin in order to display PDF documents. Adobe Reader and Foxit Reader, for example, provide exactly such a plugin. Detection of PDF plugins occurs rapidly and "on the fly" (OTF). It involves checking the navigator.mimetypes array or instantiating an ActiveXObject (for Internet Explorer).

There are some browsers, however, that have a built-in PDF viewer. They are able to display PDF documents without any plugin at all:

   1) Chrome 6 has introduced a built-in PDF viewer. You have to enable it in the browser. When you do, the "application/pdf" item will be present in the mimetypes array.

   2) Safari/Mac has a built-in PDF viewer.

   3) Safari/iPad has a built-in PDF viewer.

For Safari/Mac and the iPad, detection of PDF support requires inserting a small dummy PDF <object> tag into the web page. This detection usually occurs "not on the fly" (NOTF).

There are probably other browsers as well that have (or will have) a built-in PDF viewer.



Background info

PluginDetect's Generic PDF Reader Detector will try to determine if your browser can display a PDF document. It will do so regardless of whether your browser is using the Adobe Reader plugin or a 3rd party PDF plugin (such as Foxit Reader). If no PDF plugin is present, then the detector will look for a built-in PDF viewer.

Please note that this PDF detector is not perfect. We discuss the individual cases below:

1) Non - Internet Explorer browsers + Adobe Reader plugin: can be detected by PluginDetect. We simply check the mimetypes array to verify that "application/pdf" is present and enabled.

2) Non - Internet Explorer browsers + 3rd party PDF reader plugins: can be detected by PluginDetect. We simply check the mimetypes array to verify that "application/pdf" is present and enabled.

3) Internet Explorer + Adobe Reader plugin: can be detected by PluginDetect for IE 6+. We instantiate the ActiveX object to verify the plugin presence. The Adobe Reader plugin is an approved control in IE 7+, and hence no security popup appears in the browser when the ActiveX control is instantiated.

4) Internet Explorer + 3rd party PDF reader plugins: Theoretically can be detected in IE 6 and lower, without causing a security popup. Since IE 6 is a dead browser, there is not much point in even trying to detect 3rd party plugins in IE 6.
   For IE 7+, we CANNOT test for 3rd party plugins in some generic way without triggering a security popup. The plugin authors could make their plugin detectable in IE if they wanted to, but most of them have not bothered to do so. And unfortunately, IE does not have a navigator.mimeTypes array to tell us if the "application/pdf" mimetype is present.
   So, this is a case that PluginDetect cannot really handle. PluginDetect.isMinVersion( ) will thus return -1.5, which means we do not know whether or not PDF support is available.

5) Non - Internet Explorer browsers + built-in PDF viewer: can be detected by PluginDetect. In cases such as this, the navigator.mimetypes array may or may not have an "application/pdf" item. If there is no "application/pdf" item in the array, PluginDetect will try to instantiate an empty PDF file (1 pixel by 1 pixel). If the instantiation works, then the browser probably supports PDF documents.



OTF vs NOTF

We can say that PDF detection is performed either "on the fly" (OTF) or "not on the fly" (NOTF) in your script. Any single line of Javascript code that is able to both initiate and complete PDF detection is said to be OTF. No Javascript code is executed by the browser in between the initiation and the completion of the pdf detection. All PDF plugins (Such as Adobe Reader, Foxit Reader, etc..) are detected using OTF.

For NOTF, the browser is able to execute Javascript code in between the initiation and the completion of PDF detection. In other words, after you initiate detection the browser will keep executing Javascript commands while you are waiting for the PDF results. NOTF usually only occurs for browsers that have built in PDF capabilities.



A few PluginDetect commands for Reader detection

PluginDetect.getVersion('PDFReader', DummyPDF): [Returns null]
   Returns null only because PluginDetect will not attempt to detect any plugin version. The reason is that there are multiple vendors for PDF readers, and they use different version numbers. Also, a plugin version is irrelevant when the browser has built-in PDF support and thus requires no plugin.

PluginDetect.isMinVersion('PDFReader', minVersion, DummyPDF): [Returns number]
   Returns 0 if browser can display PDF documents. The PDF reader version is unknown.
   Returns -0.5 if detection has been initiated but is not yet completed. The -0.5 number only occurs for NOTF detection. It is not known yet whether the browser can display PDF documents. When the detection has been completed, the isMinVersion() method will return a different number.
   Returns -1 if PDF reader is not installed / not enabled.
   Returns -1.5 if PluginDetect is unable to determine whether browser can display PDF documents or not. For the time being, the -1.5 result occurs only for Internet Explorer when Adobe Reader is not installed. There may or may not be a 3rd party PDF reader installed, but PluginDetect has no way of knowing.
   Returns -2 if ActiveX is disabled (for Internet Explorer, this prevents plugin detection).
   Returns -3 if you supplied a bad input argument to the isMinVersion() method.

PluginDetect.onDetectionDone('PDFReader', f, DummyPDF): [Returns number]
   This method is capable of doing both OTF and NOTF plugin detection. NOTF is used for browsers that have native PDF support, such as Safari/ iPad and Safari/Mac. In order for this method to perform NOTF detection, you must specify the DummyPDF input argument.
   The method will initiate plugin detection if needed, and will execute the event handler f after the plugin detection results become available. The event handler f automatically receives the PluginDetect object as an input argument such that we have f(PluginDetect){ ... }.
   This method is useful as sometimes PDF detection results are available at unpredictable times - meaning that PDF detection is not always possible "on the fly". Hence, the onDetectionDone() method will wait as long as necessary until the PDF detection has completed before executing handler f. You are free to use getVersion() and isMinVersion() inside handler f to see the detection results.
   Returns 1 if plugin detection is done (OTF) and handler f has been executed.
   Returns 0 if plugin detection is not done yet (NOTF) and so handler f has not been executed yet.
   Returns -1 if error (plugin name input argument not specified correctly).

PluginDetect.beforeInstantiate('PDFReader', f):
   Executes the event handler f immediately before PluginDetect attempts to instantiate the plugin. [By instantiate, we mean that an instance of the plugin is inserted into your web page. This will cause the plugin to start up and run, assuming it is installed.] The event handler automatically receives the PluginDetect object as an input argument such that we have f(PluginDetect){ ... }.
  Sometimes during detection, it may be necessary for PluginDetect to instantiate (or attempt to instantiate) the plugin. Should this attempt be neccessary, the event handler f will run first, and then the plugin will attempt to instantiate. [Note: If the plugin is installed and enabled, then it instantiates. If it is not installed or not enabled, then it will not instantiate. Either way, the handler f will run before the attempt is made.]
  In order for the beforeInstantiate() method to work correctly, you must place it BEFORE detection is started for the plugin. In other words, use it before getVersion(pluginName), isMinVersion(pluginName), and onDetectionDone(pluginName). As an example:
       var PD = PluginDetect;
       var F1 = function($){ ... };        // $ input arg is the PluginDetect object
       PD.beforeInstantiate('PDFReader', F1);
       var F2 = function($){ var version = $.getVersion('PDFReader''); alert(version); };
       PD.onDetectionDone('PDFReader'', F2, 'empty.pdf');

PluginDetect.onWindowLoaded( f ):
   Executes the event handler f after the browser window has fully loaded, and after the plugin detection results are available. The event handler f automatically receives the PluginDetect object as an input argument such that we have f(PluginDetect){ ... }. You are free to use getVersion(), isMinVersion(), onDetectionDone(), and beforeInstantiate() inside event handler f.

Event handler f without user input arguments: If the user does not specify any input arguments for event handler f, then the relevant PluginDetect methods are in the format of
       PluginDetect.onDetectionDone(pluginName, f, ...)
       PluginDetect.onWindowLoaded(f)
       PluginDetect.beforeInstantiate(pluginName, f)

When the handler f is executed it automatically receives the PluginDetect object as input such that we have f(PluginDetect){ ... }.

Event handler f with user input arguments: You may specify up to 3 inputs (ie. arg1, arg2, and arg3) for the event handler. The trick is to use an array such as [f, arg1, arg2, arg3]. The relevant PluginDetect methods are in the format of
       PluginDetect.onDetectionDone(pluginName, [f, arg1, arg2, arg3], ...)
       PluginDetect.onWindowLoaded( [f, arg1, arg2, arg3] )
       PluginDetect.beforeInstantiate(pluginName, [f, arg1, arg2, arg3])

When the handler f is executed it automatically receives the PluginDetect object as input such that we have f(PluginDetect, arg1, arg2, arg3){ ... }.



PluginDetect.getInfo('PDFReader', DummyPDF): [object]
   Returns an object with several useful properties. The properties are listed below. To simplify matters, we assign this object to a variable:
    var INFO = PluginDetect.getInfo('PDFReader', DummyPDF);

INFO.OTF: [number]
   Returns 0 if PDF Reader detection has been performed on the fly (OTF).
   Returns 1 if PDF Reader detection is being performed not on the fly (NOTF) but is not completed yet.
   Returns 2 if PDF Reader detection has been performed not on the fly (NOTF) and is complete.

INFO.DummyPDFused: [Boolean]
   Returns true if the DummyPDF file was used by PluginDetect during detection. The DummyPDF was temporarily inserted into the web page as a 1 pixel x 1 pixel <object> tag.
   Returns false if the DummyPDF was not used during detection.



minVersion: [string or number input argument]
Use a value of '0' here because PluginDetect does not know or care what the PDF reader plugin version is.

DummyPDF: [string input argument, optional but strongly recommended] 
This is the path/filename to an empty PDF document that is temporarily inserted into a web page. It is used by PluginDetect to see if a browser has PDF capability. You may download the DummyPDF file here. You are free to rename the DummyPDF file to whatever you wish, as long as the .pdf extension remains the same. We tried to make the file as small as possible.
   Please note that the path of DummyPDF is relative to your HTML web page only! If you are using isMinVersion() in an external javascript file, the path of DummyPDF is NOT relative to the javascript file - it is still relative to the HTML web page. For example,
           DummyPDF = 'empty.pdf' means the file is in the same folder as your web page.
           DummyPDF = 'ABC/empty.pdf' means the file is in a subfolder ABC.
   Because DummyPDF is usually used during NOTF detection, it is recommended that you use DummyPDF as an input argument to the onDetectionDone( ) method.



Example using onDetectionDone( )

In order to be able to detect PDF capability on the widest variety of browsers, you should use the onDetectionDone( ) method. An example of how to use this is as follows:

var $$ = PluginDetect;
var DummyPDF = 'empty.pdf';

// We assume here that a <div id="pdfresult"></div> is in the <body> tag somewhere, so
// that we have somewhere to place the results from the PDF detection.

var output = 'pdfresult';

function displayPDFresults($$){
    var status = $$.isMinVersion('PDFReader', 0);
    var msg = 'PDF Reader status: ';

    if (status >= 0) msg += 'installed & enabled'
    else if (status==-1) msg += 'not installed or not enabled'
    else if (status == -1.5) msg += 'unknown'
    else if (status == -2) msg += 'Please enable ActiveX in Internet Explorer so that we can detect your plugins'
    else if (status==-3) msg+='error...bad input argument to PluginDetect method'
    else msg += 'unknown';

    msg += '<br/>Browser has "application/pdf" in navigator.mimeTypes array: ' +
         ($$.hasMimeType("application/pdf") ? 'true' : 'false');

    // Get extra info on the plugin.
    var INFO = $$.getInfo ? $$.getInfo('PDFReader') : null;
    if (INFO){
         msg += '<br/>PDF detection: ';
         if (INFO.OTF == 0) msg += 'completed ON THE FLY (OTF)';
         else if (INFO.OTF == 2) msg += 'completed NOT ON THE FLY (NOTF)';
         else msg += 'not completed yet, requires NOTF detection';

         msg += '<br/>DummyPDF file was used for detection in this browser: ';
         msg += (INFO.DummyPDFused ? 'true' : 'false');
     };

     var N = document.getElementById(output);
     if (N) N.innerHTML += msg;
};


// Display results when PDF detection is completed
$$.onDetectionDone('PDFReader', displayPDFresults, DummyPDF);


A few things of interest to note for the above example.

1) The PDF detector at the very top of this page uses onDetectionDone( ). Feel free to use the script in your own web page if you wish.

2) DummyPDF only needs to be specified for the very first method that is executed by the browser. In this example, that would be the onDetectionDone( ) method. We did not need to specify DummyPDF for the isMinVersion( ) method inside event handler displayPDFresults, because isMinVersion( ) is executed after onDetectionDone( ). [Of course, you are free to use DummyPDF in both isMinVersion( ) and onDetectionDone( ) if you wish].
   As a general rule, I would recommend you only use DummyPDF with the onDetectionDone( ) method. The reason is that DummyPDF is usually used during NOTF detection, and NOTF is best handled using the onDetectionDone( ) method.

3) Sometimes, the isMinVersion('PDFReader') method will return -1.5. This means that PluginDetect is unable to determine whether a PDF reader is installed or not. The -1.5 result occurs only for Internet Explorer when Adobe Reader is not installed.
   When Adobe Reader is not installed in Internet Explorer, then we have 2 possible cases: i) no PDF reader is installed at all, or ii) a 3rd party PDF reader is installed. Since we are presently unable to detect 3rd party PDF readers in IE, we thus cannot distinguish between i) and ii).

4) PluginDetect actually uses 2 different techniques to detect PDF capability in a browser. The 1st technique is to check for a PDF plugin, which is what most people are familiar with.
   If no PDF plugin is found, then a 2nd technique is used. PluginDetect will insert the 'empty.pdf' document (1 pixel x 1 pixel) into the web page to see if the browser can display it. This 2nd technique is usually intended for browsers that have a built in PDF capability, such as Safari/iPad, Safari/Mac, etc...

5) If the browser in question does not have a PDF plugin, and does not have "application/pdf" in the mimetypes array, but does have a built in PDF capability, then PluginDetect will use the 'empty.pdf' file to perform NOTF detection. The disadvantage for this particular browser is that PluginDetect must wait for the browser window to fully load (ie. window.onload event fires) before it can determine that the browser is PDF capable. This may be a problem if you have some large images in the same web page that take a long time to download from the server.
   One possible way around that is you could place the PluginDetect script inside a frame (or iframe) and do your detection within that frame. PluginDetect would thus only need to wait for the frame to fully load. An example of this iframe technique is given here.



How to verify DummyPDF path & filename

Sometimes it's nice to verify that the path and filename of DummyPDF were correctly specified. The way to verify this is to select the "Verify DummyPDF [path/]name" option when generating the PluginDetect script.

When the PluginDetect script is generated with this option, and you then use this script in your own plugin detection web page, a box will appear at the very top of your web page. This box will display the contents of the DummyPDF file, assuming you specified the DummyPDF path and filename correctly. If not, then the DummyPDF input argument may have a problem.
  
When you are done verifying the DummyPDF path and filename, you should generate another PluginDetect script without the "Verify DummyPDF [path/]name" option, and use that script in your own plugin detection web page.


Notes: The "Verify DummyPDF [path/]name" option ...

1) is only for testing, debugging, & verification purposes. It is not to be used when doing normal PDF detection.

2) will only be of use to you if your browser is able to display PDFs (either via a plugin or a built-in PDF viewer).

3) may not work with every browser, but you only need it to work on ONE browser in order to verify the DummyPDF path and filename.

4) when used with Internet Explorer, it might require the DummyPDF file to be on a web server in order for verification to work properly.
   For non-Internet Explorer browsers, it appears to make no difference whether the DummyPDF file is on your local hard drive or on a web server. The DummyPDF verification will work either way.
   Perhaps this behavior for Internet Explorer is just a small bug. But the user should be aware of this issue nonetheless.




Home