<?php

/**
 *
 * FusionCharts Exporter - 'SVG Conversion Resource' handles
 * FusionCharts (since XTT) Server Side Export feature that
 * helps FusionCharts JavaScript charts to get exported.
 *
 *
 *    @author FusionCharts
 *    @description FusionCharts Exporter (Server-Side - PHP)
 *    @version 0.0.0.1 [ 32 December 2012 ]
 *
 */
/**
 *  ChangeLog / Version History:
 *  ----------------------------
 *
 *
 *  1.0.0.0 [ 31 December 2012 ]
 *
 *
 * 	FEATURES:
 *       - Integrated with new Export feature of FusionCharts XT & FusionCharts Exporter v 2.0
 *       - can save to server side directory
 *       - can provide download or open in browser window/frame other than _self
 *
 * 	ISSUES:
 *
 *
 *
 *
 *
 */
/**
 * Copyright (c) 2012 Infosoft Global Private Limited
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
/**
 *  GENERAL NOTES
 *  -------------
 *
 *  Chart would POST export data (which consists of encoded image data stream,
 *  width, height, background color and various other export parameters like
 *  exportFormat, exportFileName, exportAction, exportTargetWindow) to this script.
 *
 *  The script would process this data using appropriate resource files build
 *  export binary (PDF/image)
 *
 *  It either saves the binary as file to a server side directory or push it as
 *  Download or open in a new browser window/frame.
 *
 *
 */
/**
 *   @requires	index.php  A file that includes this resource
 *              Java 1.3+ & Apache Batik rasterizer class: Export JavaScript charts
 *              (http://xmlgraphics.apache.org/batik/)
 *
 *
 *   Details
 *   -------
 *
 *   The resource files would have these things as common:
 *
 *   	a) a constant - MIMETYPES that would have a string
 *         containing semicolon separated key value pairs.
 * 		   Each key can be a format name specified in the
 * 		   HANDLERASSOCIATIONS constant. The associated value
 * 		   would be the mimetype for the specified format.
 *
 * 		   e.g. define("MIMETYPES","jpg=image/jpeg;jpeg=image/jpeg;png=image/png;gif=image/gif");
 *
 *
 * 		b) a constant - EXTENSIONS that again contain a string of
 * 		   semicolon separated key value pair. Each key would again be the
 * 		   format name and the extension would be the file extension.
 *
 * 		   e.g. define("EXTENSIONS","jpg=jpg;jpeg=jpg;png=png;gif=gif");
 *
 *
 *      c) a function  - exportProcessor ( $stream , $meta )
 * 		   It would take the FusionCharts exncoded image string as $stream &
 * 		   an associative array $meta containging width, height and bgColor keys.
 *
 *         The function would return an object of mixed type which would contain
 * 		   the processed binary/relevant export object.
 *
 *
 * 		d) a function - exportOutput ( $exportObj, $exportSettings, $quality=1 )
 *         It would take the processed export object and other export setting as parameter.
 *         Moreover, it would take an optional parameter - $quality (in scale of 0 to 1).
 *         By Default, the $quality is passed as 1 (best quality)
 *
 * 		   The function would return the file path on success or return false on failure.
 *
 *      [ The other code in the resource file can be anything that support this architecture ]
 *
 */
// =============================================================================
// ==                  Constants and  Variables                               ==
// =============================================================================
// ==============================================================================
//   Users are recommended NOT to perform any editing beyond this point.       ==
// ==============================================================================

ini_set('magic_quotes_gpc', 'off');

/* ------------------------- EXPORT RESOURCES -------------------------------- */

// This constant lists the mime types related to each export format this resource handles
// The value is semicolon separated key value pair for each format
// Each key is the format and value is the mime type
define("MIMETYPES", "jpg=image/jpeg;jpeg=image/jpeg;gif=image/gif;png=image/png;pdf=application/pdf;svg=image/svg+xml");
// This constant lists all the file extensions for the export formats
// The value is semicolon separated key value pair for each format
// Each key is the format and value is the file extension
define("EXTENSIONS", "jpg=jpg;jpeg=jpg;gif=gif;png=png;pdf=pdf;svg=svg");

define('TEMP_PATH', 'temp/');
define('BATIK_PATH', 'batik/batik-rasterizer.jar');
define('INKSCAPE_PATH', '/usr/bin/inkscape');
define('CONVERT_PATH', '/usr/bin/convert'); // imagemagic
// =============================================================================
// ==                             Public Functions                            ==
// =============================================================================
class stitchImageCallback {
   private $imageData;

   function __construct($imageData) {
       $this->imageData = $imageData;
   }

   public function callback($matches) {
       $imageRet = '';
       $imageName = explode('/', $matches['2']);
       $imageName = array_pop($imageName);

       foreach ($this->imageData as $key => $value) {
           if ($value->name .'.'.$value->type == $imageName) {
               $imageRet = $value->encodedData;
           }
       }
       if ($imageRet == '') {
           return '';
       }
       return $matches[1] . $imageRet;
   }
}

/**
* The function is use to stitch the image to the SVG when downloaded as SVG
* @param  [string] $svg       [SVG with image link]
* @param  [array] $imageData [Image datauri array]
* @return [string]            [SVG with imageDatauri]
*/
function stitchImageToSvg ($svg, $imageData) {
   if($imageData != null) {
        $imageData = json_decode($imageData);
        $callback = new stitchImageCallback($imageData);
        return preg_replace_callback("/(<image[^>]*xlink:href *= *[\"']?)([^\"']*)/i", array($callback, 'callback'), $svg);
   } else {
        return $svg;
   }

}
/**
 *  Gets Export data from FCExporter - main module and build the export binary/objct.
 *  @param	$stream 	(string) export image data in FusionCharts compressed format
 *      	$meta		{array)	Image meta data in keys "width", "heigth" and "bgColor"
 *              $exportParams   {array} Export related parameters
 *  @return 			image object/binary
 */
function exportProcessor($stream, $meta, $exportParams, $imageData=null) {

    // get mime type list parsing MIMETYPES constant declared in Export Resource PHP file
    $ext = strtolower($exportParams["exportformat"]);
    $ext2 = '';
    $mimeList = bang(@MIMETYPES);
    $mimeType = $mimeList[$ext];

    // prepare variables
    if (get_magic_quotes_gpc()) {
        $stream = stripslashes($stream);
    }

    // create a new export data
    $tempFileName = md5(rand());
    if ('jpeg' == $ext || 'jpg' == $ext) {
        $ext = 'png';
        $ext2 = 'jpg';
    }

    $tempInputSVGFile = realpath(TEMP_PATH) . "/{$tempFileName}.svg";
    $tempOutputFile = realpath(TEMP_PATH) . "/{$tempFileName}.{$ext}";
    $tempOutputJpgFile = realpath(TEMP_PATH) . "/{$tempFileName}.jpg";
    $tempOutputPngFile = realpath(TEMP_PATH) . "/{$tempFileName}.png";

    if ($ext != 'svg') {

        // width format for batik
        $width = @$meta['width'];
        $height = @$meta['height'];

        $size = '';
        if (!empty($width) && !empty($height)) {
            $size = "-w {$width} -h {$height}";
        }
        // override the size in case of pdf output
        if ('pdf' == $ext) {
            $size = '';
        }

        //batik bg color format
        $bg = @$meta['bgColor'];
        if ($bg) {
            $bg = " --export-background=".$bg;
        }

        // generate the temporary file
        if (!file_put_contents($tempInputSVGFile, $stream)) {
            die("Couldn't create temporary file. Check that the directory permissions for
			the " . TEMP_PATH . " directory are set to 777.");
        }

        // do the conversion
        //$command = "java -jar ". BATIK_PATH ." -m $mimeType $width $bg $tempInputSVGFile";
        $command = INKSCAPE_PATH . "$bg --without-gui {$tempInputSVGFile} --export-{$ext} $tempOutputFile {$size}";

        //echo $command;exit;
        $output = shell_exec($command);
        if ('jpg' == $ext2) {
            $comandJpg = CONVERT_PATH . " -quality 100 $tempOutputFile $tempOutputJpgFile";
            $tempOutputFile = $tempOutputJpgFile;

            $output .= shell_exec($comandJpg);
        }

        // catch error
        if (!is_file($tempOutputFile) || filesize($tempOutputFile) < 10) {
            $return_binary = $output;
            raise_error($output, true);
        }
        // stream it
        else {
            $return_binary = file_get_contents($tempOutputFile);
        }

        // delete temp internal image files if exist
        $imageData = json_decode($imageData);
        if ($imageData) {
            foreach ($imageData as $key => $value) {
                $tempInternalImage = realpath(TEMP_PATH) . "/{$value->name}.{$value->type}";
                if (file_exists($tempInternalImage)) {
                    unlink($tempInternalImage);
                }
            }
        }

        // delete temp files
        if (file_exists($tempInputSVGFile)) {
            unlink($tempInputSVGFile);
        }
        if (file_exists($tempOutputFile)) {
            unlink($tempOutputFile);
        }
        if (file_exists($tempOutputPngFile)) {
            unlink($tempOutputPngFile);
        }

        // SVG can be streamed back directly
    } else if ($ext == 'svg') {
        $stream = stitchImageToSvg($stream, $imageData);
        $return_binary = $stream;
    } else {
        raise_error("Invalid Export Format.", true);
    }

    // return export ready binary data
    return @$return_binary;
}

/**
 *  exports (save/download) SVG to export formats.
 *  @param	$exportObj 		(mixed) binary/objct exported by exportProcessor
 * 	@param	$exportSettings	(array) various server-side export settings stored in keys like
 * 					"type", "ready" "filepath" etc. Required for 'save' expotAction.
 * 					For 'download' action "filepath" is blank (this is checked to find
 * 					whether the action is "download" or not.
 * 	@param	$quality		(integer) quality factor 0-1 (1 being the best quality). As of now we always pass 1.
 *
 *  @return 				false is fails. {filepath} if succeeds. Only returned when action is 'save'.
 */
function exportOutput($exportObj, $exportSettings, $quality = 1) {

    // calls svgparser function that saves/downloads binary
    // store saving status in $doneExport which receives false if fails and true on success
    $doneExport = filesaver($exportObj, @$exportSettings ['filepath']);

    // check $doneExport and if true sets status to {filepath}'s value
    // set false if fails
    $status = ( $doneExport ? basename(@$exportSettings ['filepath']) : false );

    // return status
    return $status;
}

/**
 *  emulates imagepng/imagegif/imagejpeg. It saves data to server
 *  @param	$exportObj 	(resource) binary exported by exportProcessor
 *  @param	$filepath	(string) Path where the exported is to be stored
 *                              when the action is "download" it is null.
 *
 *  @return     (boolean) false is fails. true if succeeds. Only returned when action is 'save'.
 */
function filesaver($exportObject, $filepath) {

    // when filepath is null the action is 'download'
    // hence write the  bimary to response stream and immediately terminate/close/end stream
    // to prevent any garbage that might get into response and corrupt the  binary
    if (!@$filepath)
        die($exportObject);

    // open file path in write mode
    $fp = @fopen($filepath, "w");

    if ($fp) {
        // write  binary
        $status = @fwrite($fp, $exportObject);
        //close file
        $fc = @fclose($fp);
    }

    // return status
    return (bool) @$status;
}

/**
 * Converts Hex color values to rgb
 *
 * @param string $h Hex values
 * @param string $sep rgb value separator
 * @return string
 */
function hex2rgb($h, $sep = "") {
    $h = str_replace("#", "", $h);

    if (strlen($h) == 3) {
        $r = hexdec(substr($h, 0, 1) . substr($h, 0, 1));
        $g = hexdec(substr($h, 1, 1) . substr($h, 1, 1));
        $b = hexdec(substr($h, 2, 1) . substr($h, 2, 1));
    } else {
        $r = hexdec(substr($h, 0, 2));
        $g = hexdec(substr($h, 2, 2));
        $b = hexdec(substr($h, 4, 2));
    }
    $rgb = array($r, $g, $b);
    if ($sep) {
        $rgb = implode($sep, $rgb);
    }
    return $rgb;
}

return 'true';
