Generare JPEG website screenshot in Laravel

Aici este locul unde puteti scrie despre orice probleme /intrebari, in limita bunului simt, care nu au legatura cu subiectele din celelalte forumuri, sau cu materialele de pe site.
andras
Mesaje: 428

Generare JPEG website screenshot in Laravel

Va urez LA MULTI ANI in 2018!
Intrebare: cum pot genera un fisier imagine (JPEG) dintr-un View (fisier HTML) in Laravel 5.4 si sa-l salvez pe server intr-o locatie?
Cu codul de bare a fost mai simplu, am generat in Laravel un cod de bare:

Cod: Selectaţi tot

$barcode = DNS2D::getBarcodePNG($vanz->id.'
       '.date('M j, Y G:i:s', strtotime($vanz->created_at)), 'QRCODE');
apoi am aplicat:

Cod: Selectaţi tot

$imgb64 = base64_decode($barcode);
si am salvat fisierul pe server:

Cod: Selectaţi tot

$filenamebarcode = 'barcode_'.$vanz->id.'.jpeg';
Storage::disk('barcode')->put($filenamebarcode, $imgb64);
Dar acum trebuie sa fac factura (in HTML) si sa generez tot o imagine direct din html. Cum fac asta? Multumesc.

cata1241
Arunca o privire aici: https://stackoverflow.com/questions/757 ... creenshots
Nu e ceva usor, dar se poate.

MarPlo
Salut
Poti incerca cu html2canvas.
- Scriptul din arhiva: html2canvas_screenshoot.zip (92 KB)
Sau:

1. Ia libraria html2canvas.js de la: https://html2canvas.hertzen.com/ si salveaz-o intr-un fisier pe server, de exemplu: html2canvas.js
2. Adauga urmatorul cod javascript in pagina la care vrei sa generezi screenshoot (detalii in comentariile din cod).

Cod: Selectaţi tot

<script src="html2canvas.js"></script>
<script>
// <![CDATA[
var php_file ='save_screenshoot.php';  //address of php file that get and save image on server
var imgname ='screenshoot';  //name of the image to save

/* Ajax Function
 Send "data" to "php", using the method added to "via", and pass response to "callback" function
 data - object with data to send, name:value; ex.: {"name1":"val1", "name2":"2"}
 php - address of the php file where data is send
 via - request method, a string: 'post', or 'get'
 callback - function called to proccess the server response
*/
function ajaxSend(data, php, via, callback) {
  var ob_ajax =  (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');  //XMLHttpRequest object

  //put data from 'data' into a string to be send to 'php'
  var str_data ='isajax=1';
  for(var k in data){
    k = k.toString();
    if(data[k] || data[k] ==''){
      str_data +='&'+ k +'='+ data[k].toString().replace(/\?/g, '%3F').replace(/=/g, '%3D').replace(/&/g, '%26').replace(/[ ]+/g, '%20').replace(/[\+]/g, '%2B');
    }
  }

  //send data to php
  ob_ajax.open(via, php, true);
  if(via =='post') ob_ajax.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
  ob_ajax.send(str_data);

  //check the state request, if completed, pass the response to callback function
  ob_ajax.onreadystatechange = function(){
    if (ob_ajax.readyState == 4) callback(ob_ajax.responseText);
  }
}

//Uses HTML2Canvas to capture screenshoot of <body> content
html2canvas(document.body).then(canvas => {
  //get base64 string data of the screenshoot
  var base64image = canvas.toDataURL('image/jpeg');

  //set data that will be send with ajaxSend() to php (base64 image-data of the canvas, and image-name)
  var img_data = {cnvimg:base64image, imgname:imgname};

  //send image-data to php file, then alert response
  ajaxSend(img_data, php_file, 'post', function(resp){
    alert(resp);
  });
});
// ]]>
</script>
3. Creaza un fisier php "save_screenshoot.php" cu acest cod:

Cod: Selectaţi tot

<?php
define('UPLOAD_DIR', 'uploads/');  //Upload folder

//get properly base64 image data passed via post in 'cnvimg'
$cnvimg = trim(strip_tags($_POST['cnvimg']));
$cnvimg = str_replace(['data:image/jpeg;base64,', ' '], ['', '+'], $cnvimg);

//set image name from 'imgname', or unique name set with uniqid()
$imgname = (isset($_POST['imgname']) && !empty(trim($_POST['imgname']))) ? trim(strip_tags($_POST['imgname'])) : uniqid();

//get image data from base64 and save it on server
$data = base64_decode($cnvimg);
$file = UPLOAD_DIR . $imgname .'.jpg'; 
$save = file_put_contents($file, $data);

//output response
echo $save ?'Image: '. $file .' successfully saved.' :'Unable to save the file.';
- Succes.

MarPlo
O varianta imbunatatita a codului prezentat mai sus e la pagina de la adresa:
coursesweb.net/javascript/html2canvas-save-page-screenshoot-server

- Sa-ti fie de folos.

andras
Am reusit dupa ce am adaptat-o putin sa fie compatibila cu Laravel, acum functioneaza bine. Multumesc!

MarPlo
Ma bucura ca ti-a fost de folos.
Daca se poate, posteaza si varianta adaptata pentru Laravel.

andras
In save_screenshoot.php am modificat numai UPLOAD_DIR, dar am desfiintat save_screenshoot.js si am pus toate functiile in fisierul html factura.blade.php (in sectiunea @section('scripts')), care genereaza factura (pe acest fisierul userul nu intervine pentru ca toate variabilele sint preluate, doar este vizualizat si aplic click() la butoanele invizibile). Acest fisier are peste 200 linii (cu comentarii):

Cod: Selectaţi tot

@extends('main')

@section('title', 'Factura')

@section('stylesheets')
@endsection

@section('content')
  <style media="screen">
  .latime {
    width: 40px;
  }
  hr {
    display: block;
    margin-top: 0.5em;
    margin-bottom: 0.5em;
    margin-left: auto;
    margin-right: auto;
    border-style: inset;
    border-width: 1px;
  }
</style>

<div class="col-md-9 distanta" id="factura" style="background-color:white; border:none;">
  <input type="hidden" name="fact" id="fact" value="factura_{{ $vanz->id }}">
  <input type="hidden" name="idvinz" id="idvinz" value="{{ $vanz->id }}">
  <input type="hidden" name="iduser" id="iduser" value="{{ $vanz->user->id }}">
  <br><br><br>

  <div class="col-md-6" style="font-size:16px;font-weight:bold;">
    <h2> FACTURA</h2>
    Serie BSO   Numar {{ $vanz->id }}<br>
    Data: {{ date('M j, Y', strtotime($vanz->created_at)) }} &nbsp;&nbsp;&nbsp;&nbsp;Scadent la: {{ date('M j, Y', strtotime($vanz->created_at)) }}
  </div>
  <div class="col-md-6">
    <br><br><br>
    <h4>- RON -</h4>
  </div>
  <br><br><br><br><br><br><br><br>


  <div class="col-md-11">
    <div class="col-md-6">
      Furnizor
    </div>
    <div class="col-md-6">
      Client
    </div>
    <hr>
  </div>


  <div class="col-md-11">
    <div class="col-md-6" >
      <h4>SRL</h4>
      <span style="font-weight:bold;"> CIF</span> &nbsp;&nbsp; RC J30/ Capital soc. 200 RON <br>
      str. BISTRITEI nr. 9  <br>
      Telefon <br>
      Banca GARANTIBANK INTL NV ; IBAN: 
      Trezoreria Municipiului 
      <br><br>
    </div>
    <div class="col-md-6">
      <h4>{{ $vanz->last_name.' '.$vanz->first_name}}</h4>
      {{ $vanz->user->oras.'; '.$vanz->user->adresa.'; tel.'.$vanz->user->telefon.'; e-mail.'.$vanz->user->email.'; (ID_user = '.$vanz->user->id.')'}}
    </div>

  </div>

  <div class="col-md-11">
    <table class="table" style="border:none; border-collapse: collapse;">
      <hr>
        <tr>
          <th class="latime">Nr.crt.</th>
          <th>Denumire produse/ servicii</th>
          <th>UM</th>
          <th>Cantitate</th>
          <th>Pret unitar</th>
          <th>Valoare</th>
          <th>TVA({{$vanz->tva}}%) </th>
        </tr>
        <tr>
          <td>1</td>
          <td>{{ $vanz->abonament->denabon }}</td>
          <td></td>
          <td>1</td>
          <td>{{ number_format($vanz->pret/(1+($vanz->tva/100)), 2) }}</td>
          <td>{{ number_format($vanz->pret/(1+($vanz->tva/100)), 2) }}</td>
          <td>{{ number_format($vanz->pret-($vanz->pret/(1+($vanz->tva/100))), 2) }}</td>
        </tr>
        </table>
        <div class="" style="height:400px;">

        </div>

        <table class="table" style="border:none; border-collapse: collapse;">
          <td colspan="2"> SRL - ARNOLD</td>
          <td></td>
          <td></td>
          <td></td>
          <td>{{ number_format($vanz->pret/(1+($vanz->tva/100)), 2) }}</td>
          <td>{{ number_format($vanz->pret-($vanz->pret/(1+($vanz->tva/100))), 2) }}</td>
        </tr>
        <tr>
          <td colspan="2">Client:&nbsp;&nbsp;{{ $vanz->last_name.' '.$vanz->first_name}}</td>
          <td></td>
          <td></td>
          <td><h4>Total</h4></td>
          <td></td>
          <td><h4>{{ number_format($vanz->pret, 2) }}<h4></td>
          </tr>
        <hr>
      </table>
      <hr>
      <br><br><br>
    </div>
  </div>
  <div id="scrn_btn_img1" style="text-align:center;margin:8px auto; display:none;">
    <button id="btn_save_scrht1" onclick="myFunction();">Ssalveaza factura
    </button><h4 id="scrn_img1"></h4>
  </div>
@endsection

@section('scripts')
//from: https://coursesweb.net/
  {!! Html::script('js/html2canvas.js') !!}
  <script type="text/javascript">
  function myFunction() {
    var idvinz = document.getElementById('idvinz').value;
    var iduser = document.getElementById('iduser').value;
    var token = '{{ Session::token() }}';
    var urlEdit = '{{ route("factura") }}';

    $.ajax({
      method: 'GET',
      url: urlEdit,
      data: {idvinz: idvinz, iduser: iduser, _token: token}
    })
    .done(function (msg) {
      //
    });
  }
  </script>

  <script type="text/javascript">
  var scrn_elm ='#factura'; //for example: #id_elm
  //name of the PNG image with the screenshoot to save on server
  //here, page name without extension
  //var scrn_img = location.pathname.match(/[^\/]+$/i)[0].replace(/\.(.*?)$/i, '');
  var scrn_img = document.getElementById('fact').value;
  //object that get the screenshoot
  var save_scrht = new saveScreenshoot({elm:scrn_elm, img:scrn_img});
  document.getElementById('btn_save_scrht').click();

  function saveScreenshoot(ob){
    var php_file ='save_screenshoot.php';
    //address of php file that get and save image on server
    var html_elm =(ob && ob.elm) ? ob.elm :'body'; //css selector of html element to get screenshoot
    var imgname =(ob && ob.img) ? ob.img : location.pathname.match(/[^\/]+$/i)[0].replace(/\.(.*?)$/i, ''); //name of the image to save (page name without extension)

    /* Ajax Function
    Send "data" to "php", using the method added to "via", and pass response to "callback" function
    data - object with data to send, name:value; ex.: {"name1":"val1", "name2":"2"}
    php - address of the php file where data is send
    via - request method, a string: 'post', or 'get'
    callback - function called to proccess the server response
    */
    function ajaxSend(data, php, via, callback) {
      var ob_ajax = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'); //XMLHttpRequest object

      //put data from 'data' into a string to be send to 'php'
      var str_data ='isajax=1';
      for(var k in data){
        k = k.toString();
        if(data[k] || data[k] ==''){
          str_data +='&'+ k +'='+ data[k].toString().replace(/\?/g, '?').replace(/=/g, '=').replace(/&/g, '&').replace(/[ ]+/g, ' ').replace(/[\+]/g, '+');
        }
      }

      //send data to php
      ob_ajax.open(via, php, true);
      if(via =='post') ob_ajax.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
      ob_ajax.send(str_data);

      //check the state request, if completed, pass the response to callback function
      ob_ajax.onreadystatechange = function(){
        if (ob_ajax.readyState == 4) callback(ob_ajax.responseText);
      }
    }

    var getScreenshoot = function (){
      //Uses HTML2Canvas to capture screenshoot of <body> content
      html2canvas(document.querySelector(html_elm)).then(canvas => {
        //get base64 string data of the screenshoot
        var base64image = canvas.toDataURL('image/jpeg');

        //set data that will be send with ajaxSend() to php (base64 image-data of the canvas, and image-name)
        var img_data = {cnvimg:base64image, imgname:imgname};

        //send image-data to php file, then alert response
        ajaxSend(img_data, php_file, 'post', function(resp){
          var resp = JSON.stringify(resp) ||{};
          if(resp.re && scrn_img) scrn_img.innerHTML ='<a href="'+resp.re+'" target="_blank">See Screenshoot</a>';
          else if(resp.er) alert(resp.er);
        });
      });
    }

    //add button Save-Screenshoot in the page to call getScreenshoot() on click
    var js_save_scrht = document.getElementById('factura');
    //  if(js_save_scrht){
    factura.insertAdjacentHTML('beforebegin', '<div id="scrn_btn_img" style="text-align:center;margin:8px auto; "><button id="btn_save_scrht" style="display:none; ">Save Screenshoot</button><h4 id="scrn_img"></h4></div>');
    var scrn_btn_img = document.getElementById('scrn_btn_img');
    var btn_save_scrht = document.getElementById('btn_save_scrht');
    var scrn_img = document.getElementById('scrn_img');
    if(btn_save_scrht) btn_save_scrht.addEventListener('click', (e)=>{
      scrn_btn_img.style.display ='none';
      getScreenshoot();

      //window.setTimeout(function(){ scrn_btn_img.style.display ='block';}, 1000);
    });

    //}
    alert('Factura a fost trimisa pe e-mail.');
  }
  document.getElementById('btn_save_scrht1').click();
  </script>
@endsection


andras
Salut,
Revin cu o noua problema: cum fac ca dimensiunea fisierului .jpeg sa fie aceeasi indiferent de de device-ul de pe care generez factura? As vrea sa fie format A4, in prezent cind generez de pe laptop dimensiunea este normala, dar cind generez de pe un smartphone latimea este mult mai mica, randeaza in functie de device-ul folosit. Optiunile .col-xs-* nu ajuta. Multumesc.

MarPlo
Pentru screenshoot cu dimensiuni fixe indiferent de device, incearca sa setezi valori fixe pentru optiunile windowWidth si windowHeight, intr-un obiect ca al doilea argument la apelarea functiei html2canvas().
In codul tau ar veni asa:

Cod: Selectaţi tot

html2canvas(document.querySelector(html_elm), {windowWidth:800, windowHeight:600})
- Optiunile care pot fi configurate direct in html2canvas() le gasesti in documentatie, la: html2canvas configuration options.

Subiecte similare