<?php
/**
 *    Signature to Image: A supplemental script for Signature Pad that
 *    generates an image of the signature’s JSON output server-side using PHP.
 *
 * @project       ca.thomasjbradley.applications.signaturetoimage
 * @author        Thomas J Bradley <hey@thomasjbradley.ca>
 * @link          http://thomasjbradley.ca/lab/signature-to-image
 * @link          http://github.com/thomasjbradley/signature-to-image
 * @copyright     Copyright MMXI–, Thomas J Bradley
 * @license       New BSD License
 * @version       1.0.1
 */

/**
 *    Accepts a signature created by signature pad in Json format
 *    Converts it to an image resource
 *    The image resource can then be changed into png, jpg whatever PHP GD supports
 *
 *    To create a nicely anti-aliased graphic the signature is drawn 12 times it's original size then shrunken
 *
 * @param    string|array $json
 * @param    array $options OPTIONAL; the options for image creation
 *                          imageSize => array(width, height)
 *                          bgColour => array(red, green, blue)
 *                          penWidth => int
 *                          penColour => array(red, green, blue)
 *
 * @return    object
 */
function sigJsonToImage($json, $options = [])
{
    $defaultOptions = [
        'imageSize' => [198, 55]
        , 'bgColour' => [0xff, 0xff, 0xff]
        , 'penWidth' => 2
        , 'penColour' => [0x14, 0x53, 0x94]
        , 'drawMultiplier' => 12
    ];

    $options = array_merge($defaultOptions, $options);

    $img = imagecreatetruecolor($options['imageSize'][0] * $options['drawMultiplier'], $options['imageSize'][1] * $options['drawMultiplier']);
    $bg = imagecolorallocate($img, $options['bgColour'][0], $options['bgColour'][1], $options['bgColour'][2]);
    $pen = imagecolorallocate($img, $options['penColour'][0], $options['penColour'][1], $options['penColour'][2]);
    imagefill($img, 0, 0, $bg);

    if (is_string($json)) {
        $json = json_decode(stripslashes($json));
    }

    foreach ($json as $v)
        drawThickLine($img, $v->lx * $options['drawMultiplier'], $v->ly * $options['drawMultiplier'], $v->mx * $options['drawMultiplier'], $v->my * $options['drawMultiplier'], $pen, $options['penWidth'] * ($options['drawMultiplier'] / 2));

    $imgDest = imagecreatetruecolor($options['imageSize'][0], $options['imageSize'][1]);
    imagecopyresampled($imgDest, $img, 0, 0, 0, 0, $options['imageSize'][0], $options['imageSize'][0], $options['imageSize'][0] * $options['drawMultiplier'], $options['imageSize'][0] * $options['drawMultiplier']);

    imagedestroy($img);

    return $imgDest;
}

/**
 *    Draws a thick line
 *    Changing the thickness of a line using imagesetthickness doesn't produce as nice of result
 *
 * @param    object $img
 * @param    int $startX
 * @param    int $startY
 * @param    int $endX
 * @param    int $endY
 * @param    object $colour
 * @param    int $thickness
 *
 * @return    void
 */
function drawThickLine($img, $startX, $startY, $endX, $endY, $colour, $thickness)
{
    $angle = (atan2(($startY - $endY), ($endX - $startX)));

    $dist_x = $thickness * (sin($angle));
    $dist_y = $thickness * (cos($angle));

    $p1x = ceil(($startX + $dist_x));
    $p1y = ceil(($startY + $dist_y));
    $p2x = ceil(($endX + $dist_x));
    $p2y = ceil(($endY + $dist_y));
    $p3x = ceil(($endX - $dist_x));
    $p3y = ceil(($endY - $dist_y));
    $p4x = ceil(($startX - $dist_x));
    $p4y = ceil(($startY - $dist_y));

    $array = [0 => $p1x, $p1y, $p2x, $p2y, $p3x, $p3y, $p4x, $p4y];
    imagefilledpolygon($img, $array, (count($array) / 2), $colour);
}
