Як зробити скріншот дива з JavaScript?


175

Я будую щось, що називається "вікторина HTML". Він повністю працює на JavaScript, і це дуже круто.

Зрештою, з’являється вікно результатів із написом «Ваші результати:», і він показує, скільки часу вони зайняли, який відсоток вони отримали та скільки запитань вони отримали прямо з 10. Я хотів би мати кнопку, на якій написано "Захоплення результатів" і запропонуйте йому якось зробити знімок екрана або щось з іншого, а потім просто покажіть зображення, зняте на сторінці, де вони можуть клацнути правою кнопкою миші та "Зберегти зображення як".

Я б дуже хотів це зробити, щоб вони могли поділитися своїми результатами з іншими. Я не хочу, щоб вони "копіювали" результати, тому що вони можуть легко змінити це. Якщо вони змінить те, що написано на зображенні, добре.

Хтось знає спосіб зробити це чи щось подібне?


2
Погляньте на phantomjs.org . Використовуючи його, ви можете створити повне зображення сторінки HTML на сервері та надати користувачеві посилання для завантаження.
Джошуа

Приємний HTML-вміст статті для перетворення зображень та завантаження codepedia.info/…
Satinder singh

Відповіді:


98

Ні, я не знаю способу "зробити скріншот" елемента, але те, що можна зробити, - це намалювати результати вікторини в елемент "холст", а потім використовувати функцію HTMLCanvasElementоб'єкта, toDataURLщоб отриматиdata: URI із вмістом зображення.

Коли вікторина завершена, зробіть це:

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 */

Коли користувач натискає "Захопити", зробіть це:

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

Це відкриє нову вкладку чи вікно із "скріншотом", що дозволяє користувачеві зберегти його. Немає можливості викликати діалогове вікно "зберегти як", тож це найкраще, що ви можете зробити на мою думку.


Дякую!! Я нічого не знаю про полотно, але я це навчусь. Як я можу використовувати ефекти малювання Canvas 2D? Не могли б ви мені допомогти у цьому? Дуже дякую! :)
Натан

5
Спробуйте документацію Mozilla, насправді це досить просто: слід розробити
Делан Азабані,

Замість того, щоб відкрити його в новому вікні / вкладці, чи можу я відкрити його в діалоговому вікні? (Як плагін для лайтбокс Fancybox?)
Натан

Так, ви можете мати вбудований діалог з imgякий має свій srcнабір до data:URI. Однак це насправді не потрібно - ви можете просто поставити canvasсебе в діалогове вікно вбудованого; користувачі можуть клацнути правою кнопкою миші та зберегти поточний стан у вигляді зображення.
Делан Азабані

Дякую :) Я можу використовувати версію зображення, щоб вони змогли клацнути правою кнопкою миші та натиснути "Зберегти зображення як"
Натан

89

Це розширення @ Датана в відповідь , використовуючи html2canvas і FileSaver.js .

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


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

Цей блок коду очікує натискання кнопки з ідентифікатором btnSave. Коли він є, він перетворює widgetdiv у елемент полотна, а потім використовує інтерфейс FileSaver SaveAs () FileAver (через FileSaver.js у веб-переглядачах, які не підтримують його спочатку), щоб зберегти div як зображення під назвою "Dashboard.png".

Приклад такої роботи доступний у цьому загадку .


7
Мені потрібно було додати посилання на: html2canvas, зберігання файлів, blob, canvas-toBlob. Після цього це спрацювало. Дякую!
sirthomas

1
Дивовижно, це повинна бути прийнята відповідь. Прямий підключення n play.
ргшеной

Чи знаєте ви, як це працювало б із tri.js? У мене є div, що рендер / полотно Three.js знаходиться в (renderer.domElement), а потім діви поверх цього. Мені хотілося б зробити знімок батьківського DIV і все захопити? Чи можливо це? Дякую!
Rankinstudio

1
Чи можете ви уникнути появи зображень у вашому домені? Не можна просто перейти до завантаження відразу?
кулан

1
Для мене це спрацювало чудово з першої спроби, і навіть виглядає як оригінальний стиль CSS тощо. Дивно. Досить віртуальний знімок екрана з таким рівнем точності. Я використав CDN для 2-х бібліотек, які мені довелося додати: <! - html2canvas -> <script src = " cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/… > <! - fileaver - > <script src = " cdn.jsdelivr.net/npm/file-saver@2.0.2/dist/… >
OG Sean

13

Після годинних досліджень я нарешті знайшов рішення зробити знімок екрана елемента, навіть якщо origin-cleanФЛАГ встановлений (для запобігання XSS), тому ви навіть можете захоплювати, наприклад, Google Maps (в моєму випадку). Я написав універсальну функцію, щоб отримати скріншот. Крім того, вам потрібна бібліотека html2canvas ( https://html2canvas.hertzen.com/ ).

Приклад:

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

Майте на увазі, console.log()і ви alert()не отримаєте вихід, якщо розмір зображення великий.

Функція:

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

де ви визначили функцію html2canvas
Bharathi

Я інтегрував бібліотеку html2canvas (див. Посилання в моєму дописі), перш ніж буде досягнуто функції getScreenshotOfElement (). Наприклад, з <script> -таг. Просто завантажте html2canvas і скопіюйте його у свій проект.
помаранчевий01

@ orange01 - Я досі не в змозі захопити вуличні смуги карти Google. Це лише скріншот кнопки збільшення та зменшення масштабу, карта та текст супутника чи можете ви допомогти зробити повну карту. Спасибі
Farhan Sahibole

7

Якщо ви хочете мати діалогове вікно "Зберегти як", просто переведіть зображення в php-скрипт, який додає відповідні заголовки

Приклад сценарію "все в одному" 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>

3

Ви не можете зробити знімок екрана: це дозволить вам зробити безвідповідальний ризик для безпеки. Однак ви можете:

  • Робіть справи на стороні сервера та генеруйте зображення
  • Намалюйте щось подібне до Canvas та надайте зображення (у веб-переглядачі, який його підтримує)
  • Використовуйте іншу бібліотеку малюнків, щоб намалювати зображення безпосередньо (повільно, але він працюватиме в будь-якому браузері)

Дякую! Я піду з полотном, оскільки я не знаю жодної "бібліотеки малюнків" і не знаю, як це зробити. Я не дуже хороший у полотні, але спробую.
Натан

2
Вибачте, що я повинен прокоментувати це, оскільки він походить від google, але WTF "безвідповідальний ризик безпеки" я можу запитати, чому, якщо ви дозволите JavaScript зробити знімок екрана або зняти в межах заданих шнурів і повернути кодовані ним дані BASE64 як рядок, немає проблем із безпекою
Barkermn01

@MartinBarker Я міг (наприклад) перетягнути чиюсь сторінку Facebook у кадрі, а потім зробити знімок екрана. Зазвичай iframe на різних сторінках не є частиною доступного DOM для запобігання XSS, але постачальнику браузера буде набагато важче зупинити його в такому випадку.
bgw

2
@MartinBarker Javascript може передавати дані зловмисному джерелу, не помічаючи навіть користувача, тоді як "екран друку" контролюється користувачем, а не деяким довільним не довіреним веб-сайтом.
bgw

2
Який удар. @PiPeep, Якщо веб-сторінка може завантажувати iFrame Facebook, вже існує ізоляція, чому б не розширити таку ізоляцію за допомогою API скріншоту? напр. Div.ToPNG (), де згаданий вище iFrame вибілений? Це не безвідповідальний ризик безпеки, він просто там не вбудований, і ніхто не працював через "потенційні" проблеми конфіденційності / безпеки при розробці такого вбудованого API скріншоту. Це було б надзвичайно корисно для безлічі випадків використання, наприклад, підтримка веб-додатків інтранет.
Тодд

3
var shot1=imagify($('#widget')[0], (base64) => {
  $('img.screenshot').attr('src', base64);
});

Погляньте на пакет htmlshot , а потім глибоко перевірте розділ на стороні клієнта :

npm install htmlshot

цей проект htmlshot все ще підтримується? Посилання на github від npm, схоже, не існує. Чи є ще один веб-сайт для нього?
whatsTheDiff

@whatsTheDiff:: дайте мені свої вимоги, і будьте впевнені, що я допоможу вам. оскільки я автор цієї бібліотеки.
Abdennour TOUMI

2
Спасибі @ abdennour-toumi. Я щойно зробив встановлення npm, щоб переглянути код. Схоже, він використовує html2canvas, який я намагався, і у мене виникають проблеми в IE, а також завдяки SVG та складності моєї сторінки. Так виглядає, що ця бібліотека не допоможе мені в цьому плані.
whatsTheDiff

4
Ваш клієнт повинен уникати IE .. скажіть це!
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>

цитата


1

Це простий ви можете використовувати цей код для зйомки екрана певної області, яку ви повинні визначити з ідентифікатором div у html2canvas. Я використовую тут 2 div-:

div id = "car"
div id = "chartContainer",
якщо ви хочете захоплювати лише автомобілі, то використовуйте автомобіль, я захоплю тут машину, тільки ви можете змінити charterContainer для захоплення графіка html2canvas ($ ( "#car") скопіюйте та вставте цей код

<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>


1
Чому jQuery включається двічі і чому включений інтерфейс jQuery? Чесно кажучи, jQuery тут взагалі не потрібен з того, що я можу сказати. document.getElementById('car')абоdocument.querySelector('#car')
Натан

насправді я працюю над своїм проектом. тому я просто забуваю про видалення бібліотеки і нічого.
Рудра Пратап Сінгх

0

Наскільки я знаю, ви не можете цього зробити, я можу помилитися. Однак я би зробив це за допомогою php, генерувати JPEG за допомогою стандартних функцій php, а потім відображати зображення, не повинно бути дуже важким завданням, однак залежить від того, наскільки яскравий вміст DIV


ОП ніколи не припускав, що він використовує обробку на сервері, хоча якби він був, це було б добре.
Делан Азабані

Так, на жаль, я не можу використовувати серверні речі. Я, мабуть, піду з однією з відповідей вище. Але дякую! :)
Натан

-3

Наскільки я знаю, це неможливо за допомогою JavaScript.

Що ви можете зробити для кожного результату, створіть скріншот, збережіть його десь і вкажіть користувача, натиснувши на результат збереження. (Я думаю, що результату немає лише 10, тому не дуже важливо створити 10 jpeg зображення результатів)


Дякую за відповідь :) Ти маєш рацію! Я можу просто створити 10 зображень у форматі JPG, а потім, як тільки вони натиснуть кнопку, вони покажуть зображення для збереження. Єдина проблема полягає в тому, що коли вони починають вікторину, вони повинні ввести своє ім’я, і я відображаю це через тестування, а наприкінці у вікні результатів відображається їх ім'я, і ​​він пише коментар на кшталт "Ставати краще" і т. д. я не зміг би вписати їх ім'я на зображення чи я б?
Натан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.