Bagaimana cara mengambil screenshot div dengan JavaScript?

175

Saya sedang membangun sesuatu yang disebut "Kuis HTML". Ini sepenuhnya dijalankan pada JavaScript dan itu cukup keren.

Pada akhirnya, kotak hasil muncul yang mengatakan "Hasil Anda:" dan itu menunjukkan berapa banyak waktu yang mereka ambil, berapa persen yang mereka dapatkan, dan berapa banyak pertanyaan yang mereka dapatkan dari 10. Saya ingin memiliki tombol yang mengatakan "Capture hasil" dan minta entah bagaimana mengambil tangkapan layar atau semacamnya dari div, dan kemudian hanya menunjukkan gambar yang diambil pada halaman di mana mereka dapat mengklik kanan dan "Simpan gambar sebagai."

Saya benar-benar ingin melakukan ini sehingga mereka dapat membagikan hasilnya kepada orang lain. Saya tidak ingin mereka "menyalin" hasilnya karena mereka dapat dengan mudah mengubahnya. Jika mereka mengubah apa yang tertulis di gambar, oh well.

Adakah yang tahu cara melakukan ini atau yang serupa?

Nathan
sumber
2
Lihatlah phantomjs.org . Dengan menggunakannya, Anda dapat menghasilkan gambar lengkap dari halaman HTML di sisi server, dan memberikan tautan kepada pengguna untuk mengunduh.
Joshua
Artikel bagus, konten HTML untuk konversi gambar, dan unduh codepedia.info/…
Satinder singh
2
npmjs.com/package/dom-to-image
Stack Underflow

Jawaban:

99

Tidak, saya tidak tahu cara untuk 'screenshot' elemen, tapi apa yang bisa Anda lakukan, adalah gambar hasil kuis menjadi elemen kanvas, kemudian gunakan HTMLCanvasElementobjek toDataURLfungsi untuk mendapatkan data:URI dengan isi gambar itu.

Ketika kuis selesai, lakukan ini:

var c = document.getElementById('the_canvas_element_id');
var t = c.getContext('2d');
/* then use the canvas 2D drawing functions to add text, etc. for the result */

Ketika pengguna mengklik "Ambil", lakukan ini:

window.open('', document.getElementById('the_canvas_element_id').toDataURL());

Ini akan membuka tab atau jendela baru dengan 'tangkapan layar', memungkinkan pengguna untuk menyimpannya. Tidak ada cara untuk memohon semacam dialog 'simpan sebagai', jadi ini yang terbaik yang dapat Anda lakukan menurut saya.

Delan Azabani
sumber
Terima kasih!! Saya tidak tahu apa-apa tentang kanvas, tetapi saya akan mempelajarinya. Bagaimana saya menggunakan efek gambar Canvas 2D? Bisakah Anda membantu saya dengan ini? Terima kasih banyak! :)
Nathan
5
Coba dokumentasi Mozilla, itu benar-benar sangat mudah diikuti: developer.mozilla.org/en/canvas_tutorial
Delan Azabani
Alih-alih membukanya di jendela / tab baru, dapatkah saya membukanya di kotak dialog inline? (Seperti plugin lightbox Fancybox?)
Nathan
Yap, Anda dapat memiliki kotak dialog sebaris dengan imgyang telah srcditetapkan ke data:URI. Namun, itu tidak benar-benar diperlukan - Anda bisa meletakkannya canvassendiri di kotak dialog inline; pengguna dapat mengklik kanan dan menyimpan status saat ini sebagai gambar.
Delan Azabani
Terima kasih :) Saya mungkin menggunakan versi gambar sehingga mereka akan dapat klik kanan dan klik "simpan gambar sebagai"
Nathan
89

Ini adalah perluasan dari jawaban @ Dathan , menggunakan html2canvas dan FileSaver.js .

$(function() { 
    $("#btnSave").click(function() { 
        html2canvas($("#widget"), {
            onrendered: function(canvas) {
                theCanvas = canvas;


                canvas.toBlob(function(blob) {
                    saveAs(blob, "Dashboard.png"); 
                });
            }
        });
    });
});

Blok kode ini menunggu tombol dengan id btnSaveuntuk diklik. Ketika itu, ia mengubah widgetdiv ke elemen kanvas dan kemudian menggunakan antarmuka saveAs () FileSaver (melalui FileSaver.js di browser yang tidak mendukungnya secara native) untuk menyimpan div sebagai gambar bernama "Dashboard.png".

Contoh kerja ini tersedia di biola ini .

Andy
sumber
7
Saya perlu menambahkan referensi ke: html2canvas, filesaver, blob, canvas-toBlob. Setelah itu berhasil. Terima kasih!
sirthomas
1
Luar biasa, ini harus menjadi jawaban yang diterima. Steker langsung dan putar.
rgshenoy
Apakah Anda tahu bagaimana ini akan bekerja dengan three.js? Saya memiliki div bahwa renderer / kanvas three.js berada di (renderer.domElement), dan kemudian divs di atas itu. Saya ingin mengambil snapshot dari DIV induk dan menangkap semuanya? Apakah ini mungkin? Terima kasih!
Rankinstudio
1
Bisakah Anda menghindari gambar muncul di DOM Anda? Tidak bisakah langsung mengunduh?
kulan
1
Ini bekerja sangat baik untuk saya pada percobaan pertama, dan bahkan terlihat seperti style CSS asli dll. Luar biasa akurat. Cukup banyak screen-shot virtual dengan tingkat akurasi ini. Saya menggunakan CDN untuk 2 perpustakaan yang harus saya tambahkan: <! - html2canvas -> <script src = " cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/… > <! - filesaver - > <script src = " cdn.jsdelivr.net/npm/[email protected]/dist/… >
OG Sean
13

Setelah berjam-jam penelitian, saya akhirnya menemukan solusi untuk mengambil tangkapan layar elemen, bahkan jika origin-cleanFLAG diatur (untuk mencegah XSS), itu sebabnya Anda bahkan dapat menangkap misalnya Google Maps (dalam kasus saya). Saya menulis fungsi universal untuk mendapatkan tangkapan layar. Satu-satunya hal yang Anda butuhkan adalah perpustakaan html2canvas ( https://html2canvas.hertzen.com/ ).

Contoh:

getScreenshotOfElement($("div#toBeCaptured").get(0), 0, 0, 100, 100, function(data) {
    // in the data variable there is the base64 image
    // exmaple for displaying the image in an <img>
    $("img#captured").attr("src", "data:image/png;base64,"+data);
});

Ingat console.log()dan alert()jangan hasilkan jika ukuran gambarnya bagus.

Fungsi:

function getScreenshotOfElement(element, posX, posY, width, height, callback) {
    html2canvas(element, {
        onrendered: function (canvas) {
            var context = canvas.getContext('2d');
            var imageData = context.getImageData(posX, posY, width, height).data;
            var outputCanvas = document.createElement('canvas');
            var outputContext = outputCanvas.getContext('2d');
            outputCanvas.width = width;
            outputCanvas.height = height;

            var idata = outputContext.createImageData(width, height);
            idata.data.set(imageData);
            outputContext.putImageData(idata, 0, 0);
            callback(outputCanvas.toDataURL().replace("data:image/png;base64,", ""));
        },
        width: width,
        height: height,
        useCORS: true,
        taintTest: false,
        allowTaint: false
    });
}
orange01
sumber
di mana Anda telah mendefinisikan fungsi html2canvas
Bharathi
Saya mengintegrasikan perpustakaan html2canvas (lihat tautan di posting saya) sebelum fungsi getScreenshotOfElement () tercapai. Misalnya dengan tag <script>. Cukup unduh html2canvas dan salin ke proyek Anda.
orange01
@ orange01 - Saya masih tidak dapat menangkap jalur jalan peta google. Ini hanya screenshot tombol zoom In dan out, Peta dan teks satelit. dapatkah Anda membantu menangkap peta lengkap. Terima kasih
Farhan Sahibole
7

Jika Anda ingin memiliki dialog "Simpan sebagai", cukup kirimkan gambar ke skrip php, yang menambahkan header yang sesuai

Contoh skrip "all-in-one" script.php

<?php if(isset($_GET['image'])):
    $image = $_GET['image'];

    if(preg_match('#^data:image/(.*);base64,(.*)$#s', $image, $match)){
        $base64 = $match[2];
        $imageBody = base64_decode($base64);
        $imageFormat = $match[1];

        header('Content-type: application/octet-stream');
        header("Pragma: public");
        header("Expires: 0");
        header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
        header("Cache-Control: private", false); // required for certain browsers
        header("Content-Disposition: attachment; filename=\"file.".$imageFormat."\";" ); //png is default for toDataURL
        header("Content-Transfer-Encoding: binary");
        header("Content-Length: ".strlen($imageBody));
        echo $imageBody;
    }
    exit();
endif;?>

<script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js?ver=1.7.2'></script>
<canvas id="canvas" width="300" height="150"></canvas>
<button id="btn">Save</button>
<script>
    $(document).ready(function(){
        var canvas = document.getElementById('canvas');
        var oCtx = canvas.getContext("2d");
        oCtx.beginPath();
        oCtx.moveTo(0,0);
        oCtx.lineTo(300,150);
        oCtx.stroke();

        $('#btn').on('click', function(){
            // opens dialog but location doesnt change due to SaveAs Dialog
            document.location.href = '/script.php?image=' + canvas.toDataURL();
        });
    });
</script>
shukshin.ivan
sumber
3

Anda tidak dapat mengambil tangkapan layar: risiko keamanan yang tidak bertanggung jawab akan membuat Anda melakukannya. Namun, Anda dapat:

  • Lakukan hal-hal di sisi server dan hasilkan gambar
  • Gambar sesuatu yang mirip dengan Kanvas dan renderkan ke gambar (di browser yang mendukungnya)
  • Gunakan beberapa pustaka gambar lain untuk menggambar langsung ke gambar (lambat, tetapi akan berfungsi pada browser apa pun)
bgw
sumber
Terima kasih! Saya akan pergi dengan kanvas, karena saya tidak tahu "menggambar perpustakaan" atau saya tidak tahu bagaimana melakukannya. Aku juga tidak pandai dalam bidang kanvas, tetapi aku akan mencoba.
Nathan
2
Maaf saya harus berkomentar karena ini berasal dari google tetapi WTF "risiko keamanan yang tidak bertanggung jawab" mungkin saya bertanya mengapa, jika Anda membiarkan javascript mengambil tangkapan layar atau mengambil gambar dalam kabel yang diberikan dan mengembalikan data yang disandikan BASE64 sebagai string tanpa masalah keamanan
Barkermn01
@ MartinBarker Saya bisa (misalnya) menarik halaman Facebook seseorang dalam iframe dan kemudian tangkapan layar. Biasanya iframe lintas situs bukan bagian dari DOM yang dapat diakses untuk mencegah XSS, tetapi akan jauh lebih sulit bagi vendor browser untuk menghentikannya dalam kasus seperti ini.
bgw
2
@ MartinBarker Javascript dapat memberikan data ke sumber jahat tanpa disadari oleh pengguna, sedangkan "layar cetak" dikontrol oleh pengguna, dan bukan beberapa situs web yang tidak dipercaya sewenang-wenang.
bgw
2
Apa yang memukuli. @PiPeep, Jika halaman web dapat memuat iFrame Facebook, sudah ada isolasi, mengapa tidak memperpanjang isolasi tersebut dengan screenshot API? misalnya. Div.ToPNG (), di mana iFrame tersebut dibuang? Ini bukan risiko keamanan yang tidak bertanggung jawab, hanya saja tidak ada built-in dan tidak ada yang bekerja melalui masalah privasi / keamanan "potensial" dalam mengembangkan API tangkapan layar bawaan tersebut. Ini akan sangat berguna untuk berbagai kasus penggunaan, seperti dukungan aplikasi web intranet misalnya.
Todd
3
var shot1=imagify($('#widget')[0], (base64) => {
  $('img.screenshot').attr('src', base64);
});

Lihatlah paket htmlshot , lalu, periksa secara mendalam bagian sisi klien :

npm install htmlshot
Abdennour TOUMI
sumber
Apakah proyek htmlshot ini masih dipertahankan? Tautan github dari npm tidak terlihat masih ada. Apakah ada situs web lain untuk itu?
whatsTheDiff
@whatsTheDiff:: beri saya persyaratan Anda, dan, pastikan bahwa saya akan membantu Anda. Karena saya penulis perpustakaan ini.
Abdennour TOUMI
2
Terima kasih @ abdennour-toumi. Saya baru saja menginstal npm untuk melihat-lihat kode. Sepertinya itu menggunakan html2canvas yang telah saya coba dan mengalami masalah dengan di IE dan karena SVG's dan kompleksitas halaman saya. Tampaknya perpustakaan ini tidak akan membantu saya dalam hal ini.
whatsTheDiff
4
Pelanggan Anda harus menghindari IE .. beri tahu mereka!
Abdennour TOUMI
1
<script src="/assets/backend/js/html2canvas.min.js"></script>


<script>
    $("#download").on('click', function(){
        html2canvas($("#printform"), {
            onrendered: function (canvas) {
                var url = canvas.toDataURL();

                var triggerDownload = $("<a>").attr("href", url).attr("download", getNowFormatDate()+"电子签名详细信息.jpeg").appendTo("body");
                triggerDownload[0].click();
                triggerDownload.remove();
            }
        });
    })
</script>

kutipan

fall.lu
sumber
1

Sederhananya, Anda dapat menggunakan kode ini untuk menangkap tangkapan layar area tertentu yang harus Anda tentukan id id di html2canvas. Saya menggunakan di sini 2 div-:

div id = "mobil"
div id = "chartContainer"
jika Anda ingin hanya menangkap mobil maka gunakan mobil saya tangkap di sini mobil saja Anda dapat mengubah chartContainer untuk menangkap grafik html2canvas ($ ( '#car') salin dan tempel kode ini

<html>
    <head>


<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script>
<script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.5/jspdf.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.2.0/css/all.css" integrity="sha384-hWVjflwFxL6sNzntih27bfxkr27PmbbK/iSvJ+a4+0owXq79v+lsFkW54bOGbiDQ" crossorigin="anonymous">
<script>
    window.onload = function () {
    
    var chart = new CanvasJS.Chart("chartContainer", {
        animationEnabled: true,
        theme: "light2",
        title:{
            text: "Simple Line Chart"
        },
        axisY:{
            includeZero: false
        },
        data: [{        
            type: "line",       
            dataPoints: [
                { y: 450 },
                { y: 414},
                { y: 520, indexLabel: "highest",markerColor: "red", markerType: "triangle" },
                { y: 460 },
                { y: 450 },
                { y: 500 },
                { y: 480 },
                { y: 480 },
                { y: 410 , indexLabel: "lowest",markerColor: "DarkSlateGrey", markerType: "cross" },
                { y: 500 },
                { y: 480 },
                { y: 510 }

            ]
        }]
    });
    chart.render();
    
    }
</script>
</head>

<body bgcolor="black">
<div id="wholebody">  
<a href="javascript:genScreenshotgraph()"><button style="background:aqua; cursor:pointer">Get Screenshot of Cars onl </button> </a>

<div id="car" align="center">
    <i class="fa fa-car" style="font-size:70px;color:red;"></i>
    <i class="fa fa-car" style="font-size:60px;color:red;"></i>
    <i class="fa fa-car" style="font-size:50px;color:red;"></i>
    <i class="fa fa-car" style="font-size:20px;color:red;"></i>
    <i class="fa fa-car" style="font-size:50px;color:red;"></i>
    <i class="fa fa-car" style="font-size:60px;color:red;"></i>
    <i class="fa fa-car" style="font-size:70px;color:red;"></i>
</div>
<br>
<div id="chartContainer" style="height: 370px; width: 100%;"></div>
<script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>

<div id="box1">
</div>
</div>>
</body>

<script>

function genScreenshotgraph() 
{
    html2canvas($('#car'), {
        
      onrendered: function(canvas) {

        var imgData = canvas.toDataURL("image/jpeg");
        var pdf = new jsPDF();
        pdf.addImage(imgData, 'JPEG', 0, 0, -180, -180);
        pdf.save("download.pdf");
        
      
      
      }
     });

}

</script>

</html>

Rudra Pratap Singh
sumber
1
Mengapa jQuery disertakan dua kali, dan mengapa jQuery UI disertakan? Jujur, jQuery tidak diperlukan di sini sama sekali dari apa yang bisa saya katakan. document.getElementById('car')ataudocument.querySelector('#car')
Nathan
sebenarnya saya sedang mengerjakan proyek saya. jadi saya hanya lupa untuk menghapus perpustakaan dan tidak ada.
Rudra Pratap Singh
0

Sejauh yang saya tahu Anda tidak bisa melakukan itu, saya mungkin salah. Namun saya akan melakukan ini dengan php, menghasilkan JPEG menggunakan fungsi standar php dan kemudian menampilkan gambar, seharusnya tidak menjadi pekerjaan yang sangat sulit, namun tergantung pada seberapa mencolok isi DIV

Saulius Antanavicius
sumber
OP tidak pernah menyarankan agar ia menggunakan pemrosesan sisi server, meskipun jika ia melakukannya, ini akan baik-baik saja.
Delan Azabani
Ya, saya tidak bisa menggunakan hal-hal sisi server. Saya mungkin akan pergi dengan salah satu jawaban di atas. Tapi terima kasih :)
Nathan
-3

Sejauh yang saya tahu tidak mungkin dengan javascript.

Apa yang dapat Anda lakukan untuk setiap hasil membuat tangkapan layar, menyimpannya di suatu tempat, dan mengarahkan pengguna saat mengklik simpan hasil. (Saya kira tidak ada hasil hanya 10 jadi bukan masalah besar untuk membuat 10 jpeg gambar hasil)

seoul
sumber
Terima kasih telah menjawab :) Anda benar! Saya hanya bisa membuat 10 gambar JPG dari hasil dan kemudian setelah mereka mengklik tombol, itu akan menampilkan gambar untuk mereka simpan. Satu-satunya masalah adalah ketika mereka memulai kuis, mereka harus memasukkan nama mereka, dan saya menampilkannya melalui kuis, dan pada akhir di kotak hasil, itu menunjukkan nama mereka dan mengatakan komentar seperti "Getting Better" dll. Saya tidak akan bisa memasukkan nama mereka di gambar atau saya akan?
Nathan