Comment créer une grande image (haute qualité 300 dpi) à partir de JSON / tableau de données (Largeur,Hauteur,x,y,angels) en utilisant PHP ImageMagic / Imagick

j'ai créé un dessin (270x470) avec quelques images et du texte sur toile en utilisant FabricJs puis j'exporte toutes les images/informations de texte dans le format JSON par toile de fabricJS.la méthode toJSON () et maintenant j'ai besoin de re-dessiner cette conception sur une image de haute qualité (2790x4560) en PHP en utilisant Imagick.

FabricJS Design

JSON dataArray pour la conception ci-dessus, qui contient tous les objets de l'information comme la taille,la position,l'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"
}}

et ici mon Code Snippet pour générer une Image de haute qualité en PHP en utilisant JSON dataaarray

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();
    }
}

mes résultats de sortie (90%) est là avec la solution ci-dessus, mais comme nous pouvons voir une certaine image (ligne bleue de nombre) ne place pas à la position exacte qui devrait ressembler à la première image de conception

Imagick Design

fondamentalement ce que j'essaie de faire est, "à l'intérieur d'une boucle appelant une méthode addImage pour échelle-rotation-position chaque image sur L'image D'impression (300DPi)

Je ne suis pas sûr de ce que je manque pour obtenir le décalage exact (nouveau x, coordonnées y/position/Gauche-dessus ) après Rotation pour une image dans Imagick ou je suis objet tournant après échelle puis composer

ou Peut-être Une Formule Math comme les Mathématiques.PI:)

Question Est : Comment puis-je calculer un nouvel offset/Position en fonction du degré/Angle de Rotation après L'échelle ?

j'espère que les extraits affichés sont utiles pour tout le monde.

27
demandé sur Cœur 2015-02-28 08:18:07

3 réponses

ce n'est pas une réponse complète, mais vous vous y prenez mal.

tissu.js a déjà un moyen de sauvegarder une toile au format SVG avec la toile .toSVG () fonction. Imagick peut ouvrir des fichiers SVG et les convertir en PNG à n'importe quelle qualité que vous voulez.

il y aura un problème lors de la tentative d'inclure les bitmaps qui sont inclus dans l'image par exemple

"src": "http:\example.com/images/3f0bc771261860d917e0ad6d09cb2064.png",

je voudrais fortement recommandez de télécharger ces fichiers vous-même sur le serveur, plutôt que de permettre à Imagick de les télécharger. Non seulement cela vous donnera un meilleur contrôle sur toutes les erreurs qui peuvent se produire, mais limite également certains risques de sécurité. Permettre aux gens de télécharger des données arbitraires à partir de votre serveur et ensuite avoir ces données utilisées par une bibliothèque qui a eu de nombreux bugs avec accès à la mémoire n'est pas une bonne idée.

La façon de le faire serait de remplacer le src de l'image, avec une référence à un nom de fichier local soit avant le tissu.js crée le SVG ou vous pouvez le faire encore plus hackily après qu'il ait été converti - et quand vous faites ce remplacement générer une liste de fichiers qui doivent être téléchargés à partir d'un serveur distant.

les détails de la mise en œuvre effective sont laissés à l'exercice de L'OP.

btw il y a une chance raisonnable que quelqu'un ait déjà fait cela....avez-vous bien cherché packagist/github?

9
répondu Danack 2015-02-28 14:12:01

Crois que j'ai ce que vous cherchez, vous permettra d'avoir une fonction qui a été utilisée quelques années en arrière pour générer une image de haute qualité à partir d'une chaîne JSON. Vous devez faire les changements nécessaires. Mon extension de sortie est tiff. Et la chaîne json est faite en utilisant des versions PNG redimensionnées à 1% plus tard, je mets à l'échelle les valeurs s, y pour prendre les 100% de la taille du psd.

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;
}
0
répondu Vinu vasudev 2016-11-25 14:05:34

ici j'obtiens une solution, peut-être cela aidera d'autres comme pour moi

<?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: /q/how-can-i-wrap-text-using-imagick-in-php-so-that-it-is-drawn-as-multiline-text-20420/"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;
}
0
répondu AZinkey 2017-10-08 07:44:05