I created a design (270x470) with some pictures and text on Canvas using FabricJs then i export all pictures/text information in JSON format by fabricJS's canvas.toJSON() method And Now i need to Re-Draw that design on a High Quality (2790x4560) image in PHP using Imagick.

JSON dataArray for above design which contains all object's information like size,position,angle etc..
{
"width": "2790",
"height": "4560",
"json_data": {
"objects": [{
"type": "image",
"originX": "left",
"originY": "top",
"left": "5",
"top": "105",
"width": "260",
"height": "260",
"scaleX": "1",
"scaleY": "1",
"angle": "0",
"opacity": "1",
"src": "http:\\example.com/images/098f20be9fb7b66d00cb573acc771e99.JPG",
}, {
"type": "image",
"originX": "left",
"originY": "top",
"left": "5",
"top": "229.5",
"width": "260",
"height": "11",
"scaleX": "1",
"scaleY": "1",
"angle": "0",
"opacity": "1",
"src": "http:\\example.com/images/aeced466089d875a7c0dc2467d179e58.png",
}, {
"type": "image",
"originX": "left",
"originY": "top",
"left": "51.07",
"top": "135.58",
"width": "260",
"height": "11",
"scaleX": "1",
"scaleY": "1",
"angle": "47.41",
"opacity": "1",
"src": "http:\\example.com/images/910ce024d984b6419d708354bf3641a3.png",
}, {
"type": "image",
"originX": "left",
"originY": "top",
"left": "139.71",
"top": "104.97",
"width": "260",
"height": "11",
"scaleX": "1",
"scaleY": "1",
"angle": "89.65",
"opacity": "1",
"src": "http:\\example.com/images/88e096a82e5f8a503a71233addaff64c.png",
}, {
"type": "image",
"originX": "left",
"originY": "top",
"left": "230.78",
"top": "146.93",
"width": "260",
"height": "11",
"scaleX": "1",
"scaleY": "1",
"angle": "134.98",
"src": "http:\\example.com/images/d2c0ec738c1fec827381cfeb600bd87d.png",
}, {
"type": "image",
"originX": "left",
"originY": "top",
"left": "265.01",
"top": "240.19",
"width": "260",
"height": "11",
"scaleX": "1",
"scaleY": "1",
"angle": "179.86",
"opacity": "1",
"src": "http:\\example.com/images/3f0bc771261860d917e0ad6d09cb2064.png",
}],
"background": "#FF00FF"
}}
And here my Code Snippet for generating High Quality Image in PHP using JSON dataArray
error_reporting(E_ALL | E_STRICT);
try {
$id = $_GET['id']; // Design ID
define('DS', DIRECTORY_SEPARATOR);
$jsonDir = dirname(__FILE__) . DS . 'media' . DS . 'designs';
$printData = json_decode(file_get_contents($jsonDir . DS . $id . '.json'));
} catch (Exception $e) {
echo $e->getMessage();
}
try {
$print = new Imagick();
$print->setResolution(300, 300);
$background = (empty($printData->json_data->background)) ? 'transparent' : $printData->json_data->background;
$print->newImage($printData->width, $printData->height, new ImagickPixel($background));
$print->setImageFormat('png32');
$print->setImageUnits(imagick::RESOLUTION_PIXELSPERCENTIMETER);
} catch (Exception $e) {
echo $e->getMessage();
}
// Re-Scaling each Image/Text for Larger Canvas/Image
foreach ($printData->json_data->objects as $i => $object) {
if ($object->type == 'image') {
addImage($object, $print, $printData);
} else {
addText($object, $print, $printData);
}
}
try {
// Saving High Quality Image in (300 dpi)
$fileDir = dirname(__FILE__) . DS . 'media' . DS . 'prints';
if (!file_exists($fileDir) || !is_dir($fileDir)) {
if (!mkdir($fileDir))
die("Could not create directory: {$fileDir}\n");
}
$saved = $print->writeimage($fileDir . DS . $id . '.png');
header('Content-type: image/png');
echo $print;
} catch (Exception $e) {
echo $e->getMessage();
}
addImage();
function addImage($object, $print, $printData) {
try {
$widthScale = ($printData->width / 270);
$heightScale = ($printData->height / 470);
$fileDir = dirname(__FILE__) . DS . 'media' . DS . 'original' . DS;
$src = new Imagick($fileDir . basename($object->src));
$size = $src->getImageGeometry();
$resizeWidth = ($object->width * $object->scaleX) * $widthScale;
$resizeHeight = ($object->height * $object->scaleY) * $heightScale;
$src->resizeImage($resizeWidth, $resizeHeight, Imagick::FILTER_LANCZOS, 1);
$sizeAfterResize = $src->getImageGeometry();
$src->rotateImage(new ImagickPixel('none'), $object->angle);
$sizeAfterRotate = $src->getImageGeometry();
if (!$object->angle) {
$left = $object->left * $widthScale;
$top = $object->top * $heightScale;
} else {
switch ($object->angle) {
case $object->angle > 315:
$left = ($object->left * $widthScale);
$top = ($object->top * $heightScale);
break;
case $object->angle > 270:
$left = ($object->left * $widthScale);
$top = ($object->top * $heightScale);
break;
case $object->angle > 225:
$left = ($object->left * $widthScale);
$top = ($object->top * $heightScale);
break;
case $object->angle > 180:
$left = ($object->left * $widthScale);
$top = ($object->top * $heightScale);
break;
case $object->angle > 135:
$left = ($object->left * $widthScale);
$top = ($object->top * $heightScale);
break;
case $object->angle > 90:
$left = ($object->left * $heightScale) - ($sizeAfterRotate['width'] / 2);
$top = ($object->top * $heightScale) - ($sizeAfterRotate['width'] / 2);
break;
case $object->angle > 45:
$left = ($object->left * $widthScale) - $size['height'] * $widthScale;
$top = ($object->top * $heightScale) - $size['height'] * $heightScale;
break;
default:
$left = $object->left * $widthScale;
$top = $object->top * $heightScale;
break;
}
}
$print->compositeImage($src, Imagick::COMPOSITE_DEFAULT, $left, $top);
} catch (Exception $e) {
echo $e->getMessage();
}
}
My Output results (90%) is there with above solution, but as we can see some image (blue number line) doesn't place at exact position which should look like first design image

Basically what i am trying to do is, " Inside a Loop calling an addImage Method for scale - rotate - position each image on Print Image(300DPi)
i am not sure what i am missing to get exact offset (new x,y coordinates/position/Left-Top ) after Rotation for an image in Imagick or i am Rotating object after Scale then compose
or May be A Math Formula like Math.PI :)
Question is: How Can i Calculate New offset/Position according to Rotation Degree/Angle after Scale ?
I hope posted snippet are useful for everyone.
This is not a complete answer, but you are going about this completely wrong.
Fabric.js already has a way of saving a canvas to SVG format with the canvas.toSVG() function. Imagick can open SVG files and convert them to PNG at any quality you want.
There will be an issue when trying to include the bitmaps that are included in the image e.g.
"src": "http:\\example.com/images/3f0bc771261860d917e0ad6d09cb2064.png",
I would strongly recommend downloading these yourself on the server, rather than allowing Imagick to download them. Not only will that give you better control over any errors that may occur, but also limits some security risks. Allowing people to download arbitrary data from within your server and then having that data used by a library that has had many bugs with memory access is not a good idea.
The general way to do this would be to replace the src of the image with a reference to a local file name either before fabric.js creates the SVG or you could do it even more hackily after it's been converted - and when you do this replacement generate a list of files that need to be downloaded from a remote server.
The actual implementation details are left as an exercise for OP.
btw there is a reasonable chance someone has already done this....have you searched packagist/github thoroughly?
Think I got what you are looking for, will let you have a function which used few years back to generate a high quality image from a JSON string. You have to make necessary changes though. My output extension is tiff. And json string is made using 1% resized png versions later I scale the s, y values to take the 100% full sized psd's.
function generateDesignImage($arr_params,$arr_design){
extract($arr_params);
$images = $arr_design['sprites'];
$dir = $arr_design['options']['source_dir'];
$ext = $arr_design['options']['in_ext'];
$side = $arr_design['options']['img_side'];
$out_ext = $arr_design['options']['out_ext'];
// Canvas
$im = new Imagick();
$im->newImage(6000,6000,'transparent');
$im->setImageColorSpace(Imagick::COLORSPACE_CMYK);
//$im->setImageDepth(8);
/********************* Code for image arrangements *************************/
$i =0;
$min_X = $min_Y = 6000;
$max_X = $max_Y = 0;
$scale = 10;
foreach($images as $sprites=>$val){
$var = "img_$i";
$var = new Imagick();
$var->resizeImage($var->getImageWidth()/$scale,$var->getImageHeight()/$scale,Imagick::FILTER_LANCZOS,1,TRUE);
/************ Find out x,y,width and height *********************/
$c_width = $var->getImageWidth()/2;
$c_height = $var->getImageHeight()/2;
$x1 = ($val['x']*$scale/$val['scale'])-$c_width;
$y1 = ($val['y']*$scale/$val['scale'])-$c_height;
$x2 = ($val['x']*$scale/$val['scale'])+$c_width;
$y2 = ($val['y']*$scale/$val['scale'])+$c_height;
$min_X = ($min_X >= $x1)?$x1:$min_X;
$min_Y = ($min_Y >= $y1)?$y1:$min_Y;
$max_X = ($max_X <= $x2)?$x2:$max_X;
$max_Y = ($max_Y <= $y2)?$y2:$max_Y;
/***************************************************************/
$im->compositeImage($var, $var->getImageCompose(), $x1,$y1,imagick::MONTAGEMODE_FRAME);
$i++;
}
/**************************************************************************/
$im->setImageFormat( $out_ext );
/******************Crop to Exact Fit ********************************/
$im->cropImage ( $max_X-$min_X+100,$max_Y-$min_Y+100 ,$min_X-50 ,$min_Y-50 );
/************************************************************************/
$success1 = $im->writeImage( 'Out_image_'.$design_id.'.'.$out_ext);
$var->BorderImage(new ImagickPixel("white") , 5,5);
return $success1;
}
Here I get a solution, may be it will help others like for me
<?php
// AZinkey
ini_set('memory_limit', '1024M'); // may be need increase memory size
ini_set('display_errors', 1); // enable error display
error_reporting(E_ALL); // show all type errors
$id = $_GET['id'];
$file = $id . ".json"; // json file e.g. 1234.json
$printData = json_decode(file_get_contents($file));
$mask = "mask.png"; // a image (4395x4395) which contains 2669x4395 black fill in center
$maskImg = new Imagick($mask);
$d = $maskImg->getImageGeometry();
$maskWidth = $d['width'];
$maskHeight = $d['height'];
// Then reduce any list of integer
$cd = array_reduce(array($maskWidth, 400), 'gcd');
$r1 = $maskWidth / $cd;
$r2 = 400 / $cd;
$newPrintData['r1'] = $r1;
$newPrintData['r2'] = $r2;
try {
$print = new Imagick();
$print->setResolution(300, 300);
$background = (empty($printData->json_data->background)) ? 'transparent' : $printData->json_data->background;
$print->newImage($maskWidth, $maskHeight, new ImagickPixel($background));
$print->setImageMatte(TRUE);
$print->setImageFormat('png32');
$print->setImageUnits(imagick::RESOLUTION_PIXELSPERCENTIMETER);
} catch (Exception $e) {
echo $e->getMessage();
}
// create two array for store text & images information separately
$imageObjects = $textObjects = [];
foreach ($printData->json_data->objects as $object) {
if ($object->type == 'image') {
$imageObjects[] = $object;
} else if ($object->type == 'text') {
$imageObjects[] = $object;
}
}
foreach ($imageObjects as $object) {
addImageToLarge($object, $print, $printData, $newPrintData);
}
foreach ($imageObjects as $object) {
addTextToLarge($object, $print, $printData, $newPrintData);
}
try {
$print->setImageFormat('png');
$saveFile = $id . "_print.json"; // save large image _print.png
file_put_contents($saveFile, $print);
} catch (Exception $e) {
echo $e->getMessage();
exit();
}
function addImageToLarge($object, $print, $printData, $newPrintData) {
try {
$src = new Imagick($object->src);
$size = $src->getImageGeometry();
$resizeWidth = changeDpi(scale($object->width, $newPrintData['r1'], $newPrintData['r2']) * $object->scaleX);
$resizeHeight = changeDpi(scale($object->height, $newPrintData['r1'], $newPrintData['r2']) * $object->scaleY);
$src->resizeImage($resizeWidth, $resizeHeight, Imagick::FILTER_LANCZOS, 1);
$sizeAfterResize = $src->getImageGeometry();
$src->rotateImage(new ImagickPixel('none'), $object->angle);
$sizeAfterRotate = $src->getImageGeometry();
$left = $object->left < 0 ? -1 * abs(changeDpi(scale($object->left, $newPrintData['r1'], $newPrintData['r2']))) : changeDpi(scale($object->left, $newPrintData['r1'], $newPrintData['r2']));
$top = $object->top < 0 ? -1 * abs(changeDpi(scale($object->top, $newPrintData['r1'], $newPrintData['r2']))) : changeDpi(scale($object->top, $newPrintData['r1'], $newPrintData['r2']));
$print->compositeImage($src, Imagick::COMPOSITE_OVER, $left, $top);
} catch (Exception $e) {
echo $e->getMessage();
exit();
}
}
function addTextToLarge($object, $print, $printData, $newPrintData) {
$fnt['Times New Roman'] = "font/times_6.ttf";
$fnt['Arial'] = "font/arial_8.ttf";
$fnt['Arial Black'] = "font/ariblk_8.ttf";
$fnt['Comic Sans MS'] = "font/comic_5.ttf";
$fnt['Courier New'] = "font/cour_5.ttf";
$fnt['Georgia'] = "font/georgia_5.ttf";
$fnt['Impact'] = "font/impact_7.ttf";
$fnt['Lucida Console'] = "font/lucon_3.ttf";
$fnt['Lucida Sans Unicode'] = "font/l_4.ttf";
$fnt['Palatino Linotype'] = "font/pala_7.ttf";
$fnt['Tahoma'] = "font/tahoma_3.ttf";
$fnt['Trebuchet MS'] = "font/trebuc_3.ttf";
$fnt['Verdana'] = "font/verdana_5.ttf";
try {
$line_height_ratio = $object->lineHeight;
$resizeWidth = changeDpi(scale($object->width, $newPrintData['r1'], $newPrintData['r2']) * $object->scaleX);
$resizeHeight = changeDpi(scale($object->height, $newPrintData['r1'], $newPrintData['r2']) * $object->scaleY);
$print2 = new Imagick();
$print2->setResolution(300, 300);
$print2->newImage($resizeWidth, $resizeHeight, "transparent");
$print2->setImageVirtualPixelMethod(imagick::VIRTUALPIXELMETHOD_BACKGROUND);
$print2->setImageFormat('png32');
$print2->setImageUnits(imagick::RESOLUTION_PIXELSPERCENTIMETER);
// Instantiate Imagick utility objects
$draw = new ImagickDraw();
$color = new ImagickPixel($object->fill);
//$starting_font_size = 100*1.33;
$font_size = (($object->fontSize * $resizeWidth) / $object->width);
$draw->setFontWeight(($object->fontWeight == 'bold') ? 600 : 100 );
$draw->setFontStyle(0);
$draw->setFillColor($color);
// Load Font
//$font_size = $starting_font_size;
$draw->setFont($fnt[$object->fontFamily]);
$draw->setFontSize($font_size);
$draw->setTextAntialias(true);
$draw->setGravity(Imagick::GRAVITY_CENTER);
if ($object->stroke) {
$draw->setStrokeColor($object->stroke);
$draw->setStrokeWidth($object->strokeWidth);
$draw->setStrokeAntialias(true); //try with and without
}
$total_height = 0;
// Run until we find a font size that doesn't exceed $max_height in pixels
while (0 == $total_height || $total_height > $resizeHeight) {
if ($total_height > 0) {
$font_size--; // we're still over height, decrement font size and try again
}
$draw->setFontSize($font_size);
// Calculate number of lines / line height
// Props users Sarke / BMiner: http://stackoverflow.com/questions/5746537/how-can-i-wrap-text-using-imagick-in-php-so-that-it-is-drawn-as-multiline-text
$words = preg_split('%\s%', $object->text, -1, PREG_SPLIT_NO_EMPTY);
$lines = array();
$i = 0;
$line_height = 0;
while (count($words) > 0) {
$metrics = $print2->queryFontMetrics($draw, implode(' ', array_slice($words, 0, ++$i)));
$line_height = max($metrics['textHeight'], $line_height);
if ($metrics['textWidth'] > $resizeWidth || count($words) < $i) {
$lines[] = implode(' ', array_slice($words, 0, --$i));
$words = array_slice($words, $i);
$i = 0;
}
}
$total_height = count($lines) * $line_height * $line_height_ratio;
if ($total_height > 0) {
}
}
// Writes text to image
$x_pos = 0;
$y_pos = 0;
for ($i = 0; $i < count($lines); $i++) {
$print2->annotateImage($draw, $x_pos, $y_pos + ($i * $line_height * $line_height_ratio), $object->angle, $lines[$i]);
}
if ($object->flipX == 1)
$print2->flopImage(); // x
if ($object->flipY == 1)
$print2->flipImage(); // y
$print2->trimImage(0);
$print2->setImagePage(0, 0, 0, 0);
$print2->resizeImage($resizeWidth, 0, Imagick::FILTER_CATROM, 0.9, false);
$left = $object->left < 0 ? -1 * abs(changeDpi(scale($object->left, $newPrintData['r1'], $newPrintData['r2']))) : changeDpi(scale($object->left, $newPrintData['r1'], $newPrintData['r2']));
$top = $object->top < 0 ? -1 * abs(changeDpi(scale($object->top, $newPrintData['r1'], $newPrintData['r2']))) : changeDpi(scale($object->top, $newPrintData['r1'], $newPrintData['r2']));
$print->compositeImage($print2, Imagick::COMPOSITE_OVER, $left, $top);
//header("Content-Type: image/png");
//echo $print2;exit;
} catch (Exception $e) {
echo $e->getMessage();
exit();
}
}
//The greatest common divisor (GCD)
function gcd($a, $b) {
return $b ? gcd($b, $a % $b) : $a;
}
function changeDpi($px) {
//return ($px/96)*300;
return $px;
}
function scale($px, $r1, $r2) {
return $px * $r1 / $r2;
}
来源:https://stackoverflow.com/questions/28778396/how-to-create-a-large-high-quality-300dpi-image-from-json-array-of-data-wid