4 * Copyright (C) 2016-2017 Jerry Padgett <sjpadgett@gmail.com>
6 * LICENSE: This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * @author Jerry Padgett <sjpadgett@gmail.com>
21 * @link http://www.open-emr.org
25 * @param string|array $json
26 * @param array $options OPTIONAL; the options for image creation
27 * imageSize => array(width, height)
28 * bgColour => array(red, green, blue) | transparent
30 * penColour => array(red, green, blue)
31 * drawMultiplier => int
36 function sigJsonToImage($json, $options = array())
38 $defaultOptions = array(
39 'imageSize' => array(240,70)
40 ,'bgColour' => 'transparent'
42 ,'penColour' => array(0x14, 0x53, 0x94)
46 $options = array_merge($defaultOptions, $options);
48 $img = imagecreatetruecolor($options['imageSize'][0] * $options['drawMultiplier'], $options['imageSize'][1] * $options['drawMultiplier']);
50 if ($options['bgColour'] == 'transparent') {
51 imagesavealpha($img, true);
52 $bg = imagecolorallocatealpha($img, 0, 0, 0, 127);
54 $bg = imagecolorallocate($img, $options['bgColour'][0], $options['bgColour'][1], $options['bgColour'][2]);
57 $pen = imagecolorallocate($img, $options['penColour'][0], $options['penColour'][1], $options['penColour'][2]);
58 imagefill($img, 0, 0, $bg);
60 if (is_string($json)) {
61 $json = json_decode(stripslashes($json));
64 foreach ($json as $v) {
65 drawThickLine($img, $v->lx
* $options['drawMultiplier'], $v->ly
* $options['drawMultiplier'], $v->mx
* $options['drawMultiplier'], $v->my
* $options['drawMultiplier'], $pen, $options['penWidth'] * ($options['drawMultiplier'] / 2));
68 $imgDest = imagecreatetruecolor($options['imageSize'][0], $options['imageSize'][1]);
70 if ($options['bgColour'] == 'transparent') {
71 imagealphablending($imgDest, false);
72 imagesavealpha($imgDest, true);
75 imagecopyresampled($imgDest, $img, 0, 0, 0, 0, $options['imageSize'][0], $options['imageSize'][0], $options['imageSize'][0] * $options['drawMultiplier'], $options['imageSize'][0] * $options['drawMultiplier']);
81 * image resize function
82 * @param $file - file name to resize
83 * @param $string - The image data, as a string
84 * @param $width - new image width
85 * @param $height - new image height
86 * @param $proportional - keep image proportional, default is no
87 * @param $output - name of the new file (include path if needed)
88 * @param $delete_original - if true the original image will be deleted
89 * @param $use_linux_commands - if set to true will use "rm" to delete the image, if false will use PHP unlink
90 * @param $quality - enter 1-100 (100 is best quality) default is 100
91 * @param $cropFromTop - if false crop will be from center, if true crop will be from top
92 * @return boolean|resource
94 function smart_resize_image(
99 $proportional = false,
101 $delete_original = true,
102 $use_linux_commands = false,
106 if ($height <= 0 && $width <= 0) {
110 if ($file === null && $string === null) {
114 # Setting defaults and meta
115 $info = $file !== null ?
getimagesize($file) : getimagesizefromstring($string);
119 list($width_old, $height_old) = $info;
120 $cropHeight = $cropWidth = 0;
121 # Calculating proportionality
124 $factor = $height/$height_old;
125 } elseif ($height == 0) {
126 $factor = $width/$width_old;
128 $factor = min($width / $width_old, $height / $height_old);
131 $final_width = round($width_old * $factor);
132 $final_height = round($height_old * $factor);
134 $final_width = ( $width <= 0 ) ?
$width_old : $width;
135 $final_height = ( $height <= 0 ) ?
$height_old : $height;
136 $widthX = $width_old / $width;
137 $heightX = $height_old / $height;
138 $x = min($widthX, $heightX);
139 $cropWidth = ($width_old - $width * $x) / 2;
140 $cropHeight = ($height_old - $height * $x) / 2;
143 # Loading image to memory according to type
146 $file !== null ?
$image = imagecreatefromjpeg($file) : $image = imagecreatefromstring($string);
149 $file !== null ?
$image = imagecreatefromgif($file) : $image = imagecreatefromstring($string);
152 $file !== null ?
$image = imagecreatefrompng($file) : $image = imagecreatefromstring($string);
158 # This is the resizing/resampling/transparency-preserving magic
159 $image_resized = imagecreatetruecolor($final_width, $final_height);
160 if (($info[2] == IMAGETYPE_GIF
) ||
($info[2] == IMAGETYPE_PNG
)) {
161 $transparency = imagecolortransparent($image);
162 $palletsize = imagecolorstotal($image);
163 if ($transparency >= 0 && $transparency < $palletsize) {
164 $transparent_color = imagecolorsforindex($image, $transparency);
165 $transparency = imagecolorallocate($image_resized, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']);
166 imagefill($image_resized, 0, 0, $transparency);
167 imagecolortransparent($image_resized, $transparency);
168 } elseif ($info[2] == IMAGETYPE_PNG
) {
169 imagealphablending($image_resized, false);
170 $color = imagecolorallocatealpha($image_resized, 0, 0, 0, 127);
171 imagefill($image_resized, 0, 0, $color);
172 imagesavealpha($image_resized, true);
177 $cropHeightFinal = 0;
179 $cropHeightFinal = $cropHeight;
182 imagecopyresampled($image_resized, $image, 0, 0, $cropWidth, $cropHeightFinal, $final_width, $final_height, $width_old - 2 * $cropWidth, $height_old - 2 * $cropHeight);
183 # Taking care of original, if needed
184 if ($delete_original) {
185 if ($use_linux_commands) {
192 # Preparing a method of providing result
193 switch (strtolower($output)) {
195 $mime = image_type_to_mime_type($info[2]);
196 header("Content-type: $mime");
203 imagedestroy($image);
204 return $image_resized;
210 # Writing image according to type to the output destination and image quality
213 imagegif($image_resized, $output);
216 imagejpeg($image_resized, $output, $quality);
219 $quality = 9 - (int)((0.9*$quality)/10.0);
220 imagepng($image_resized, $output, $quality);
230 * Changing the thickness of a line using imagesetthickness doesn't produce as nice of result
237 * @param object $colour
238 * @param int $thickness
242 function drawThickLine($img, $startX, $startY, $endX, $endY, $colour, $thickness)
244 $angle = (atan2(($startY - $endY), ($endX - $startX)));
246 $dist_x = $thickness * (sin($angle));
247 $dist_y = $thickness * (cos($angle));
249 $p1x = ceil(($startX +
$dist_x));
250 $p1y = ceil(($startY +
$dist_y));
251 $p2x = ceil(($endX +
$dist_x));
252 $p2y = ceil(($endY +
$dist_y));
253 $p3x = ceil(($endX - $dist_x));
254 $p3y = ceil(($endY - $dist_y));
255 $p4x = ceil(($startX - $dist_x));
256 $p4y = ceil(($startY - $dist_y));
258 $array = array(0=>$p1x, $p1y, $p2x, $p2y, $p3x, $p3y, $p4x, $p4y);
259 imagefilledpolygon($img, $array, (count($array)/2), $colour);
265 * Associative array of options.
270 * An array of indexed coordinates [lx, ly, mx, my]
275 * Maximum image width and height.
278 public $max = array(0,0);
280 * @param string|array $json Can accept a JSON string or an array of SigPad coord objects.
281 * @param array $options
282 * title : @var string ['Signature'] Text description of the image
283 * penWidth : @var int [2] width of the line
284 * penColour : @var string ['#145394'] hexidecimal color of the signature
285 * @throws Exception If failure on JSON parsing.
287 public function __construct($json, $options = array())
289 $this->options
= array_merge($this->getDefaultOptions(), $options);
290 if (is_string($json)) {
291 $this->coords
= json_decode($json, true); // force to assoc array
292 if (is_null($this->coords
)) {
294 if (function_exists('json_last_error')) { // allow for php 5.2
295 switch (json_last_error()) {
296 case JSON_ERROR_DEPTH
:
297 $jErr = ' - Maximum stack depth exceeded';
299 case JSON_ERROR_CTRL_CHAR
:
300 $jErr = ' - Unexpected control character found';
302 case JSON_ERROR_SYNTAX
:
303 $jErr = ' - Syntax error, malformed JSON';
305 case JSON_ERROR_NONE
:
306 $jErr = ' - Unknown error';
311 throw new Exception("Cannot decode the JSON string.$jErr", 1000);
314 $this->coords
= array_map('array_values', $this->coords
); // flatten the array
315 } elseif (is_array($json)) {
316 $this->coords
= array();
317 foreach ($json as $obj) {
318 $this->coords
[] = array_values((array)$obj);
321 throw new Exception('Data passed to constructor is invalid.', 1001);
328 public static function getMimeType()
330 return 'image/svg+xml';
333 * @return array Name value pairs
335 private function getDefaultOptions()
338 'title' => 'Signature',
340 'penColour' => '#145394'
344 * Determine the maximum height and width of the image.
345 * @param array $coord
348 private function setMax($coord)
350 foreach ($coord as $i => $pt) {
351 if ($pt > $this->max
[$i%2
]) {
352 $this->max
[$i%2
] = $pt;
357 * Get the SVG line elements.
360 private function getLineElements()
363 foreach ($this->coords
as $coord) {
364 $lines .= vsprintf('<line x1="%d" y1="%d" x2="%d" y2="%d"/>', $coord);
365 $this->setMax($coord);
371 * Get the image boundaries.
372 * @param bool $axis False is x-axis, True is y-axis
375 private function getBound($axis = 0)
377 return round($this->max
[(int)$axis] +
($this->options
['penWidth'] / 2));
380 * Get the full XML SVG image.
383 public function getImage()
385 $max[0] = $this->getBound(0);
386 $max[1] = $this->getBound(1);
387 $lines = $this->getLineElements();
388 return '<?xml version="1.0"?><svg baseProfile="tiny" width="' . $this->getBound(0) . '" height="' . $this->getBound(1) . '" version="1.2" xmlns="http://www.w3.org/2000/svg"><g fill="red" stroke="' . $this->options
['penColour'] . '" stroke-width="' . (int)$this->options
['penWidth'] . '" stroke-linecap="round" stroke-lingjoin="round"><title>' . htmlspecialchars($this->options
['title']) . '</title>' . $lines . '</g></svg>';
391 * Compress the SVG using gzip.
394 public function getImageGz()
396 if (!function_exists('gzencode')) {
397 throw new Exception('Cannot get gzip image. Check that Zlib is installed.', 2000);
400 return gzencode($this->getImage(), 9);