<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>How to generate images with JpGraph library</title><link rel="stylesheet" type="text/css" href="manual.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.0"><link rel="home" href="index.html" title="JpGraph Manual"><link rel="up" href="ch05.html" title="Chapter 5. Fundamentals of dynamic graph generation"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">How to generate images with JpGraph library</th></tr><tr><td width="20%" align="left"> </td><th width="60%" align="center">Chapter 5. Fundamentals of dynamic graph generation</th><td width="20%" align="right"> </td></tr></table><hr></div><div class="sect1" title="How to generate images with JpGraph library"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2494304"></a>How to generate images with JpGraph library</h2></div></div></div>
            
            <p>The two common steps for creating and using a Graph on your Web-page are</p>
            <p>
                </p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">
                        <p>Create a script that constructs the graph, by getting the data and
                            specifying how the graph should look, the size, what colors to use, what
                            fonts to use and specifying other augmentations on the graph.</p>
                    </li><li class="listitem">
                        <p>On the HTML page where the graph(s) should be displayed include add
                            one or more <span class="markup">&lt;img&gt;</span> tags which links to the PHP graphs
                            script. Of course it is perfectly possible to call the image script
                            directly in the browser to just display the generated image in the
                            browser. This way it is possible to include any number of graphs on the
                            Web-page.</p>
                    </li></ol></div><p>
            </p>
            <div class="tip" title="Tip" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Tip</h3>
                <p>One further thing to keep in mind is that it is also possible to pass
                    arguments to the image script via the normal HTTP GET/POST arguments. </p>
                <p>For example </p>
                <p>
                    </p><pre class="screen">&lt;img src="showgraph.php?a=1&amp;b=2"&gt; </pre><p>
                </p>
                <p>This could be used to control the appearance of the image or perhaps send data
                    to the image which will be displayed. Note that this is probably not the best
                    way to send large amount of data to plot. Instead the only practical way, for
                    large data sizes, is to get all the data in the image script directly, perhaps
                    from a DB. Another alternative for large amount of data to be sent to the image
                    script is by creating a POST request to the image script. This is further
                    discussed in ?? (Getting hold of the data to be displayed)</p>
            </div>
            <div class="sect2" title="The standard steps of setting up a graph"><div class="titlepage"><div><div><h3 class="title"><a name="id2494467"></a>The standard steps of setting up a graph</h3></div></div></div>
                
                <p>When it comes to the structure of your imaging script they will generally have
                    the following structure </p>
                <p>
                    </p><div class="hl-main"><table class="hl-table" width="100%"><tr><td class="hl-gutter" align="right" valign="top"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="hl-main" valign="top"><pre><span class="hl-inlinetags">&lt;?php</span><span class="hl-code">
</span><span class="hl-comment">//</span><span class="hl-comment"> ... Include necessary headers </span><span class="hl-comment"></span><span class="hl-code">
</span><span class="hl-reserved">require_once</span><span class="hl-code"> </span><span class="hl-quotes">'</span><span class="hl-string">jpgraph.php</span><span class="hl-quotes">'</span><span class="hl-code">;
</span><span class="hl-reserved">require_once</span><span class="hl-code"> </span><span class="hl-quotes">'</span><span class="hl-string">....</span><span class="hl-quotes">'</span><span class="hl-code">;
 
</span><span class="hl-comment">//</span><span class="hl-comment"> Create the graph instance</span><span class="hl-comment"></span><span class="hl-code">
</span><span class="hl-var">$graph</span><span class="hl-code"> = </span><span class="hl-reserved">new</span><span class="hl-code"> </span><span class="hl-identifier">Graph</span><span class="hl-brackets">(</span><span class="hl-var">$width</span><span class="hl-code">,</span><span class="hl-var">$height</span><span class="hl-code">, ...</span><span class="hl-brackets">)</span><span class="hl-code">; 
 
</span><span class="hl-comment">//</span><span class="hl-comment"> Specify what scale should be used in the graph</span><span class="hl-comment"></span><span class="hl-code">
</span><span class="hl-var">$graph</span><span class="hl-code">-&gt;</span><span class="hl-identifier">SetScale</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">...</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">;
 
</span><span class="hl-comment">//</span><span class="hl-comment"> ... code to construct the graph details and plot objects</span><span class="hl-comment"></span><span class="hl-code">
 
</span><span class="hl-comment">//</span><span class="hl-comment"> Add one or many plot objects to the graph</span><span class="hl-comment"></span><span class="hl-code">
</span><span class="hl-var">$graph</span><span class="hl-code">-&gt;</span><span class="hl-identifier">Add</span><span class="hl-brackets">(</span><span class="hl-code">..</span><span class="hl-brackets">)</span><span class="hl-code">; 
 
</span><span class="hl-comment">//</span><span class="hl-comment"> ... and send back the graph to the client</span><span class="hl-comment"></span><span class="hl-code">
</span><span class="hl-var">$graph</span><span class="hl-code">-&gt;</span><span class="hl-identifier">Stroke</span><span class="hl-brackets">(</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-inlinetags">?&gt;</span></pre></td></tr></table></div><p>
                </p>
                <p>JpGraph is completely Object oriented so all calls will be action on specific
                    instances of classes. One of the fundamental classes is the <code class="code">Graph()</code>
                    class which represents the entire graph.</p>
                <p>After the creation of the <code class="code">Graph()</code> object all the code lines to
                    construct the details of the graph are added. The final method called in an
                    image script will most likely be the <code class="code">Graph::Stroke()</code> method. This
                    will send the constructed image back to the browser. A variation of this is used
                    if the graph are supposed to have image maps (CSIM). In that case the final
                    method will be <code class="code">Graph::StrokeCSIM()</code></p>
                <p>
                    </p><div class="caution" title="Caution" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Caution</h3>
                        <p>As discussed in <a class="xref" href="ch05.html#sec1.making-sense-of-HTTP-streams" title="Making sense of HTTP streams and MIME types">Making sense of HTTP streams and MIME types</a> no text can be
                            returned from an image script. Beware!</p>
                    </div><p>
                </p>
                <p>In addition to this standard usage pattern you can also choose to:</p>
                <p>
                    </p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">
                            <p>... send the graph directly to a file. This is done by specifying
                                a filename as parameter to the final <code class="code">Stroke()</code> method
                                call. See <a class="xref" href="ch05s05.html#sec2.writing-miage-to-file" title="Writing the image directly to a file">Writing the image directly to a file</a> for more detailed
                                information.</p>
                        </li><li class="listitem">
                            <p>... access the GD image handler for further image processing (also
                                needed to include the image in an PDF file, see <a class="xref" href="apc.html" title="Appendix C. FAQ">Appendix C. <i>FAQ</i></a>)</p>
                        </li><li class="listitem">
                            <p>... make use of the built-in cache system to send back a
                                previously generated image. The cache system, which lessens the
                                burden of the PHP server, works by avoiding running all the code
                                that follows the initial <code class="code">Graph()</code> call by checking if
                                the image has already been created and in that case directly send
                                back the previously created (and stored in a file) image file to the
                                browser. The filename used for the image can be either manually
                                selected or automatically created based on the script name. In
                                addition it is also possible to specify a timeout value in the
                                initial call to the Graph() constructor to indicate how long the
                                image in the cache directory should be considered valid before a new
                                image is generated. A full description of the JpGraph cache system
                                is available in <a class="xref" href="ch05s06.html" title="Efficient graph generation using the built-in cache subsystem">Efficient graph generation using the built-in cache subsystem</a>.</p>
                            <p>
                                </p><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3>
                                    <p>The cache system by default is disabled and must be
                                        enabled by setting the proper define in the file
                                            "j<code class="filename">pg-config.inc</code>"</p>
                                </div><p>
                            </p>
                        </li><li class="listitem">
                            <p>... combine several graphs in the same image using the
                                    <code class="code">MGraph()</code> class (Multi-Graph). This is an advanced
                                technique described in ??.</p>
                        </li></ol></div><p>
                </p>
            </div>
            <div class="sect2" title="Choosing the image compression format for JpGraph"><div class="titlepage"><div><div><h3 class="title"><a name="id2494641"></a>Choosing the image compression format for JpGraph</h3></div></div></div>
                
                <p>By default JpGraph automatically chooses the image format to use in the order
                    PNG, JPEG and GIF. The exact format depends on what is available on the system
                    the library is installed on. There are two ways you can influence the way the
                    graphic format is chosen:</p>
                <p>
                    </p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">
                            <p>Change the default graphic format by changing the DEFINE (in
                                    <code class="filename">jpg-config.inc.php</code>)</p>
                            <p><code class="code">DEFINE('DEFAULT_GFORMAT','auto')</code></p>
                            <p>For example; if you by default want all your images to be
                                generated with JPG encodation the define should be changed to </p>
                            <p><code class="code">DEFINE('DEFAULT_GFORMAT','jpg')</code></p>
                        </li><li class="listitem">
                            <p>By dynamically (in your script) select the wanted compression
                                format with a call to</p>
                            <p><code class="code">Image::SetImgFormat()</code></p>
                            <p>For example; if you want your image to use the JPEG format </p>
                            <p>
                                <code class="code">$graph-&gt;img-&gt;SetImgFormat('jpeg')</code></p>
                            <p> (The above line assume that you have called your variable that
                                holds the instantiated <code class="code">Graph()</code> object
                                    "<code class="code">$graph</code>"</p>
                        </li></ol></div><p>
                </p>
            </div>
            <div class="sect2" title="Sending back the image to the browser"><div class="titlepage"><div><div><h3 class="title"><a name="id2494706"></a>Sending back the image to the browser</h3></div></div></div>
                
                <p>The very last statement in almost all graph scripts is the line</p>
                <p>
                    </p><pre class="screen">$graph-&gt;Stroke();</pre><p>
                </p>
                <p>
                    </p><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3>
                        <p>Actually there are some valid exceptions to this when you do some more
                            advanced graph generation involving caching together with the CSIM
                            functionality.</p>
                    </div><p>
                </p>
                <p>This line starts the actual graph creation. All method calls up to this stage
                    has just been to set the scene for the library and specify all necessary
                    parameters. It is first when you make the call to the <code class="code">Stroke()</code>
                    method the library actually starts to build the image. Assuming there are no
                    errors detected when the image is generated the library will now take the
                    following steps in principle:</p>
                <p>
                    </p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">
                            <p>Start building the image in memory. This is done by analyzing the
                                specified parameters and making use of the supplied data in order to
                                create the various plots that have been specified.</p>
                        </li><li class="listitem">
                            <p>Check what headers are needed, i.e. what image compression are
                                used for the graph, and send that header back to the client.</p>
                            <p>The library also have to check how the library was called since if
                                it was called from the command line no MIME headers should be sent
                                back at all, just the raw image data. Running the command line
                                version of PHP will allow you to dynamically create images without
                                using a HTTP server.</p>
                        </li><li class="listitem">
                            <p>Send the actual image data representing the built up image back to
                                the client</p>
                        </li></ol></div><p>
                </p>
                <div class="warning" title="The dreaded: Headers has already been sent error" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">The dreaded: Headers has already been sent error</h3>
                    
                    <p>This is an error that everyone, and we really mean everyone, will see one
                        time or the other when producing dynamic images with PHP.</p>
                    <p>First, this is not a problem with JpGraph per se. What has happened is
                        that your PHP script which produces the image has already returned some data
                        to the client before the image header has been sent. </p>
                    <p>This is most often caused by one or more spaces before the first
                            "<code class="code">&lt;?php</code>" statement. What happens is that the server
                        normally sends back all data it finds in the files it reads. Since the
                        server no sees a space, a perfectly valid character, it will send that data
                        back to the client. However, before it does that it will automatically
                        generate a header. Since it has seen a normal character data it will
                        generate a header telling the client to expect a data stream of
                        characters.</p>
                    <p>When later JpGraph tries to send its image header the server will detect
                        that a header has already been sent and since each HTTP data stream can only
                        have one type (and hence only one header) it will generate an error message
                        which is sent back to the client.</p>
                    <p>To correct this error check your files for any output (even a single
                        space) before the call to <code class="code">Graph::Graph()</code> (or
                            <code class="code">Graph::Stroke()</code>) If you are running on older version of a
                        Windows server this problem could also be caused by blank line at the end of
                        the files. On some older Windows versions together with PHP4 it might also
                        be called by a file ending in a newline (which all the JpGraph library files
                        does) Remove the newline so that the file ends just after the final
                            "<code class="code">?&gt;</code>" Also remember that when you include external file
                        using <code class="code">include/include_once</code> and so on PHP includes the whole
                        content of the file; this content of the file also includes any potential
                        carriage return/line feed or "blank" space before "<code class="code">&lt;?php</code>"
                        and after "<code class="code">?&gt;"</code> These "dirty characters" will cause the problem
                        just described. </p>
                </div>
            </div>
            <div class="sect2" title="Writing the image directly to a file"><div class="titlepage"><div><div><h3 class="title"><a name="sec2.writing-miage-to-file"></a>Writing the image directly to a file</h3></div></div></div>
                
                <p>In addition to just streaming the file back to the browser it is also possible
                    to write the file directly to a named file. The file name is given as an
                    argument to the Graph::Stroke() method. For example as </p>
                <p><code class="code">$graph-&gt;Stroke('/tmp/myimage.png');</code></p>
                <p>There are three important things to note here</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">
                            <p>The PHP process must have write permission on the directory you
                                are trying to write the image file on. If you are running PHP
                                through your browser this means that the HTTP server process must
                                have write permission on that directory.</p>
                        </li><li class="listitem">
                            <p>The file suffix (e.g. '<code class="code">.png</code>') should match the image
                                compression type used.</p>
                        </li><li class="listitem">
                            <p>If the image is streamed directly to a file and not back to the
                                browser the script can of course return ordinary text.</p>
                        </li></ol></div>
                <div class="tip" title="Writing the image to both a file and stream it back to the browser" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Writing the image to both a file and stream it back to the
                        browser</h3>
                    
                    <p>In this case you should instead use the method
                            <code class="code">Graph::StrokeStore($aFileName)</code> which was introduced in
                        version 2.5 of the library. If you are on a previous version and for various
                        reasons cannot upgrade then you can use the following "trick" to achieve
                        this.</p>
                    <p>The idea is to use the <code class="code">_IMG_HANDLER</code> option that forces the
                            <code class="code">Graph::Stroke()</code> to just return the image handler and then
                        stop. We can then manually first send the image to the chosen file and then
                        stream it back to the browser using some internal methods in the library.
                        The following code snippet shows how this is done.
                        </p><div class="hl-main"><table class="hl-table" width="100%"><tr><td class="hl-gutter" align="right" valign="top"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="hl-main" valign="top"><pre><span class="hl-inlinetags">&lt;?php</span><span class="hl-code">
 
</span><span class="hl-comment">//</span><span class="hl-comment"> ... necessary includes ...</span><span class="hl-comment"></span><span class="hl-code">
 
</span><span class="hl-var">$graph</span><span class="hl-code"> = </span><span class="hl-reserved">new</span><span class="hl-code"> </span><span class="hl-identifier">Graph</span><span class="hl-brackets">(</span><span class="hl-number">400</span><span class="hl-code">,</span><span class="hl-number">300</span><span class="hl-brackets">)</span><span class="hl-code">;
 
</span><span class="hl-comment">//</span><span class="hl-comment"> ... code to generate a graph ...</span><span class="hl-comment"></span><span class="hl-code">
 
</span><span class="hl-comment">//</span><span class="hl-comment"> Get the handler to prevent the library from sending the</span><span class="hl-comment"></span><span class="hl-code">
</span><span class="hl-comment">//</span><span class="hl-comment"> image to the browser</span><span class="hl-comment"></span><span class="hl-code">
</span><span class="hl-var">$gdImgHandler</span><span class="hl-code"> = </span><span class="hl-var">$graph</span><span class="hl-code">-&gt;</span><span class="hl-identifier">Stroke</span><span class="hl-brackets">(</span><span class="hl-identifier">_IMG_HANDLER</span><span class="hl-brackets">)</span><span class="hl-code">;
 
</span><span class="hl-comment">//</span><span class="hl-comment"> Stroke image to a file and browser</span><span class="hl-comment"></span><span class="hl-code">
 
</span><span class="hl-comment">//</span><span class="hl-comment"> Default is PNG so use &quot;.png&quot; as suffix</span><span class="hl-comment"></span><span class="hl-code">
</span><span class="hl-var">$fileName</span><span class="hl-code"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">/tmp/imagefile.png</span><span class="hl-quotes">&quot;</span><span class="hl-code">;
</span><span class="hl-var">$graph</span><span class="hl-code">-&gt;</span><span class="hl-identifier">img</span><span class="hl-code">-&gt;</span><span class="hl-identifier">Stream</span><span class="hl-brackets">(</span><span class="hl-var">$fileName</span><span class="hl-brackets">)</span><span class="hl-code">;
 
</span><span class="hl-comment">//</span><span class="hl-comment"> Send it back to browser</span><span class="hl-comment"></span><span class="hl-code">
</span><span class="hl-var">$graph</span><span class="hl-code">-&gt;</span><span class="hl-identifier">img</span><span class="hl-code">-&gt;</span><span class="hl-identifier">Headers</span><span class="hl-brackets">(</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-var">$graph</span><span class="hl-code">-&gt;</span><span class="hl-identifier">img</span><span class="hl-code">-&gt;</span><span class="hl-identifier">Stream</span><span class="hl-brackets">(</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-inlinetags">?&gt;</span></pre></td></tr></table></div>
                </div>
            </div>
            <div class="sect2" title="Alternatives to streaming or storing the image"><div class="titlepage"><div><div><h3 class="title"><a name="id2494959"></a>Alternatives to streaming or storing the image</h3></div></div></div>
                
                <p>There are also two predefined filenames which have special meaning when
                    supplied as argument ot the <code class="code">Stoke()</code> method.</p>
                <p>
                    </p><div class="variablelist"><dl><dt><span class="term"><code class="code">_IMG_AUTO</code></span></dt><dd>
                                <p>This will create a file in the same directory as the script
                                    with the same name as the script but with the correct image
                                    extension. </p>
                            </dd><dt><span class="term"><code class="code">_IMG_HANDLER</code></span></dt><dd>
                                <p>Specifying this filename will not create a an image to file
                                    nor stream it back to the browser. Instead it will instruct the
                                        <code class="code">Stroke()</code> method to just return the handle for
                                    the GD image. This is useful if you later want to manipulate the
                                    image in ways that are not yet supported by JpGraph. For example
                                    include the image in a dynamically generated PDF file. See <a class="xref" href="apc.html" title="Appendix C. FAQ">Appendix C. <i>FAQ</i></a> for a detailed example how to
                                    include an image in a PDF generated with the "fpdf"
                                    library.</p>
                            </dd></dl></div><p>
                </p>
            </div>
            <div class="sect2" title="Forcing the browser to update your graph"><div class="titlepage"><div><div><h3 class="title"><a name="sec2.forcing-browser-update"></a>Forcing the browser to update your graph</h3></div></div></div>
                
                <p>Some browser may not send back a request to the HTTP server unless the user
                    presses "Refresh" (F5 - in most browsers). This can lead to problems that the
                    user is seeing old data since the file stamp of the script might not change but
                    the data the script is using to create the image/graph is. A simple trick is to
                    add a dummy time argument which is not used in the script. </p>
                <p>For example </p>
                <p><code class="code">&lt;img src="myimagescript.php?dummy=\'.now()."&gt;</code>
                </p>
                <p>Since the dummy argument will be a new number whenever the browser checks it
                    the browser understands that it must re-fetch the script and force the image to
                    be reloaded and redisplayed.</p>
                <p>It is also important to be aware of any internal caching the browser might do.
                    The general problem with dynamically generated images is that the image
                    generating script (file) remains the same. This makes the browser believe that
                    the data hasn\'t changed (since the script is the same) and if the browser
                    already has issued a previous GET request and has the data cached it will not
                    send a new GET if the time stamp on the file is the same since it then believes
                    it should and can use the old browser cached version.</p>
            </div>
            <div class="sect2" title="Printing the generated image"><div class="titlepage"><div><div><h3 class="title"><a name="id2495089"></a>Printing the generated image</h3></div></div></div>
                
                <p>Some browsers, most notable IE (&lt; v7) can have issues printing a dynamic
                    image. This is because the designers of IE assumed that all images are
                    traditional images that are available as static image files. Not that they could
                    be dynamically generated. This unfortunately have some implications.</p>
                <p>
                    </p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">
                            <p>IE will often (always?) re-fetch the page when preparing to print.
                                This means that a new image will be generated and is perhaps very
                                different from what the user thinks he is printing (if the data is
                                changing rapidly).</p>
                        </li><li class="listitem">
                            <p>Some older versions of IE simply refuses to print dynamic images
                                if they are not available as a static "*.png", "*.jpg" etc. file.
                                The only known workaround is to make sure to use static
                                images.</p>
                        </li></ol></div><p>
                </p>
                <p>There is one final reported problem to be aware of. Normally most browsers
                    will support "right-clicking" on an image to download the image locally.
                    However, some older versions of IE will become very confused when dynamic images
                    are used. This could manifest itself as that the file type is not the wanted,
                    for example, trying to download a "*.png" image could cause the file to be saved
                    as a "*.bmp" file instead. </p>
                <p>Newer versions of IE seems to be able to handle dynamic images much
                    better.</p>
                <p>It should also be mentioned that some older versions of FireFox (&lt; v3)
                    could in some circumstances fetch a dynamic image twice causing unnecessary load
                    on the server (See <code class="uri"><a class="uri" href="https://bugzilla.mozilla.org/show_bug.cgi?id=331126" target="_top">FireFox
                        Bugzilla</a></code>). However, there are no known issues with dynamic images in
                    current versions of FireFox and IE (i.e. IE v8).</p>
            </div>
        </div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"> </td><td width="20%" align="center"><a accesskey="u" href="ch05.html">Up</a></td><td width="40%" align="right"> </td></tr><tr><td width="40%" align="left" valign="top"> </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> </td></tr></table></div></body></html>