Візуалізація HTML до зображення


167

Чи є спосіб надати HTML на зображення, як PNG? Я знаю, що це можливо з canvas, але я хотів би надати стандартний HTML-елемент, наприклад, div.


Наприклад, створити якусь допомогу користувача. На жаль, це неможливо (з міркувань безпеки?). Вам потрібно попросити користувача натиснути PrintScreen, щоб щось зробити.
MaxArt


Я хочу використовувати HTML / CSS для розробки логотипу.
Мартін Деллі

4
@ ErnestFriedman-Hill не є дублікатом: питання, яке ви згадали, стосується Java.
Мартін Деллі

Ось покроковий посібник для перетворення HTML в IMAGE png або jpeg формату codepedia.info/2016/02/…
Satinder singh

Відповіді:


42

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

  • задавши файл HTML, генеруйте (png) зображення з прозорим фоном з командного рядка

Використовуючи Chrome без голови (версія 74.0.3729.157 на цю відповідь), це насправді просто:

"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --headless --screenshot --window-size=256,256 --default-background-color=0 button.html

Пояснення команди:

  • ви запускаєте Chrome з командного рядка (тут показано для Mac, але припускаючи подібне в Windows або Linux)
  • --headless запускає Chrome, не відкриваючи його, і закривається після завершення команди
  • --screenshotзробить знімок екрана (зверніть увагу, що він генерує файл, званий screenshot.pngу папці, де виконується команда)
  • --window-sizeдозволяють захоплювати лише частину екрана (формат є --window-size=width,height)
  • --default-background-color=0це чарівний трюк, який спонукає Chrome використовувати прозорий фон, а не білий колір за замовчуванням
  • нарешті, ви надаєте файл html (як URL-адресу або локального, або віддаленого ...)

1
Дуже хороша! Він також працює зі SVG! Я перейшов до вашого рішення врешті-решт! ;-)
Мартін Деллі

1
--screenshot='absolute\path\of\screenshot.png'працював на мене
palash

Командна лінія працювала. якщо я хочу запустити цю програму з Express js як її запустити?
Рецепти шкварки

FYI це також працює з хромом, хоча він не згадує про параметр на сторінці man.
Робін Ласхоф-Регас

Svg для мене не svg ... це лише PNG з розширенням SVG ... тому будьте уважні.
kristopolous

97

Так. HTML2Canvas існує для візуалізації HTML <canvas>(який ви можете використовувати як зображення).

ПРИМІТКА. Існує відома проблема, що це не працюватиме з SVG


Це здається цікавим, але мені не вдалося змусити його працювати, тому я вибрав рішення Джона Фішера. Дякую за інформацію, я буду дивитись цей проект у майбутньому!
Мартін Деллі

@MartinDelille: тут стаття про використання HTML2Canvas для створення IMAGE, а також ви можете завантажити її на стороні клієнта codepedia.info/2016/02/…
Satinder singh

3
dom-to-image (див. відповідь цайєна) робить набагато кращу роботу, щоб створити точну картину.
JBE

3
Це рішення дуже повільне
hamboy75

3
інше питання, якщо елемент приховано або за іншим елементом, це не спрацює
Yousef

91

Я можу порекомендувати бібліотеку dom-to-image , яка була написана виключно для вирішення цієї проблеми (я підтримую).
Ось як ви його використовуєте (дещо більше тут ):

var node = document.getElementById('my-node');

domtoimage.toPng(node)
    .then (function (dataUrl) {
        var img = new Image();
        img.src = dataUrl;
        document.appendChild(img);
    })
    .catch(function (error) {
        console.error('oops, something went wrong!', error);
    });

2
Це чудово! Будь-який спосіб подвоїти вихідний розмір?
cronoklee

Дякую! Але що саме ви маєте на увазі під "подвоєнням розміру"?
tsayen

2
Перше, що мені спадає на думку - спробуйте вивести своє зображення на SVG (використовуючи domtoimage.toSvg), потім виведіть його на полотно і спробуйте якось пограти з роздільною здатністю цього полотна. Можливо, можливо реалізувати таку функцію, як певний параметр візуалізації в самій lib, так що ви можете передавати розміри зображення в пікселях. Якщо вам це потрібно, я буду вдячний, що ви створили випуск на Github.
tsayen

8
Це набагато краще, ніж html2canvas. Дякую.
c.hughes

1
@Subho - це рядок, що містить URL з кодованими даними base64
tsayen

66

Варіантів дуже багато, і всі вони мають свої плюси і мінуси.

Варіант 1: Використовуйте одну з багатьох доступних бібліотек

Плюси

  • Перетворення відбувається досить швидко більшу частину часу

Мінуси

  • Погане відображення
  • Не виконує JavaScript
  • Немає підтримки останніх веб-функцій (FlexBox, Додаткові селектори, Веб-шрифти, Розміри коробки, Медіа-запити, ...)
  • Іноді не так просто встановити
  • Складний в масштабі

Варіант 2: Використовуйте PhantomJs і, можливо, бібліотеку обгортки

Плюси

  • Виконати Javascript
  • Досить швидко

Мінуси

  • Погане відображення
  • Немає підтримки останніх веб-функцій (FlexBox, Додаткові селектори, Веб-шрифти, Розміри коробки, Медіа-запити, ...)
  • Складний в масштабі
  • Не так легко змусити його працювати, якщо є завантажувані зображення ...

Варіант 3: Використовуйте Chrome Headless і, можливо, бібліотеку для обгортки

Плюси

  • Виконати Javascript
  • Поруч ідеальна візуалізація

Мінуси

  • Не так просто отримати бажаний результат щодо:
    • терміни завантаження сторінки
    • розміри вікна перегляду
  • Складний в масштабі
  • Досить повільно і навіть повільніше, якщо html містить зовнішні посилання

Варіант 4: Використовуйте API

Плюси

  • Виконати Javascript
  • Поруч ідеальна візуалізація
  • Швидкий при правильному використанні параметрів кешування
  • Шкала обробляється API
  • Точні терміни, вікно перегляду, ...
  • Більшу частину часу вони пропонують безкоштовний план

Мінуси

  • Не безкоштовно, якщо ви плануєте їх багато використовувати

Розкриття інформації: Я засновник ApiFlash. Я зробив усе можливе, щоб дати чесну та корисну відповідь.


2
Дякую за детальну відповідь з великою кількістю можливих рішень
bszom

wkhtmltoimage / pdf підтримує надання JavaScript. Ви можете встановити затримку javascript або дозволити wkhtml перевірити специфіку window.status (яку ви можете встановити за допомогою JavaScript, коли ви знаєте, що ваш js матеріал зроблений)
Daniel Z.

PhantomJS підтримує такі динамічні матеріали, як Карти Google. Це дійсно повний веб-браузер, лише без доданого дисплея. Однак вам доведеться трохи почекати, поки Google Map завантажить плитки з географією (я чекаю 500 мс і дозволяю людям змінити затримку - якщо цього недостатньо, знову запустити, не збільшуючи час, добре, тому що ці плитки є кешованими).
Ладислав Зіма

50

У всіх відповідях, що використовуються сторонніми бібліотеками, в той час як надання HTML зображення може бути порівняно простим у чистому Javascript. Про це навіть було написано статтю в розділі полотна на MDN.

Хитрість у цьому:

  • створіть SVG з вузлом ForeignObject, що містить ваш XHTML
  • встановити src зображення на URL-адресу даних цього SVG
  • drawImage на полотно
  • встановити дані полотна для націлювання image.src

const {body} = document

const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
canvas.width = canvas.height = 100

const tempImg = document.createElement('img')
tempImg.addEventListener('load', onTempImageLoad)
tempImg.src = 'data:image/svg+xml,' + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><foreignObject width="100%" height="100%"><div xmlns="http://www.w3.org/1999/xhtml"><style>em{color:red;}</style><em>I</em> lick <span>cheese</span></div></foreignObject></svg>')

const targetImg = document.createElement('img')
body.appendChild(targetImg)

function onTempImageLoad(e){
  ctx.drawImage(e.target, 0, 0)
  targetImg.src = canvas.toDataURL()
}

Деякі речі, які слід зазначити

  • HTML всередині SVG повинен бути XHTML
  • З міркувань безпеки SVG як URL-адреса зображення зображення виступає ізольованою областю CSS для HTML, оскільки жодні зовнішні джерела не можуть бути завантажені. Таким чином, шрифт Google, наприклад , повинен бути вбудованими з допомогою такого інструменту , як цей .
  • Навіть коли HTML всередині SVG перевищує розмір зображення, він буде правильно малювати на полотні. Але фактичну висоту неможливо виміряти з цього зображення. Рішення з фіксованою висотою буде працювати чудово, але динамічна висота потребує трохи більше роботи. Найкраще - передати дані SVG у рамку iframe (для ізольованої області CSS) та використати отриманий розмір для полотна.

Приємно! Видалення залежності від зовнішньої бібліотеки - це справді хороший шлях. Я змінив свою прийняту відповідь :-)
Мартін Деллі

Такої статті вже немає.
MSC

2
Чудова відповідь, але коментуючи стан сучасних HTML та Web API, який, як правило, виглядає як щось витягнуло когось позаду - вся функціональність технічно є, але піддається масиву (не призначений для каламбуру) дивних кодових шляхів, які нагадують нічого такого чіткого, чого б ви не очікували від добре розроблених API. У звичайному плані: найімовірніше, для браузера дозволити Documentперетворення a в растр (наприклад, a Canvas), але, оскільки ніхто не намагався його стандартизувати, ми мусимо вдатися до божевілля, як показано вище (жодного образи на автора цього код).
атп

1
Ця відповідь stackoverflow.com/questions/12637395/…, схоже, вказує на те, що ви можете зайти далеко. Mozilla та Chrome мають необмежену довжину даних, і навіть поточний IE дозволяє 4 Гб, що зводиться до приблизно 3 ГБ зображень (за рахунок base64). Але це було б добре перевірити.
Сеїті

3
- кілька швидких та брудних тестів пізніше - jsfiddle.net/Sjeiti/pcwudrmc/75965 Chrome, Edge та Firefox піднімаються на висоту не менше 10 000 пікселів, що (у цьому випадку) - це кількість символів приблизно 10 000 000 та розмір файлів у форматі png. 8 Мб. Не перевірений ретельно, але цього достатньо для більшості випадків використання.
Сеїті

13

Ви можете використовувати PhantomJS , який є безголовим вебкітом (двигун візуалізації в сафарі та (до недавнього часу) хром). Ви можете дізнатися , як зробити знімок екрана сторінок тут . Сподіваюся, що це допомагає!


Ця методика добре працює. Однак з Вашого коментаря минуло 2 роки. Чи стикалися ви з тим, що працює швидше, ніж PhantomJS? Згенерування зображення, як правило, займає 2-5 секунд у Phantom, на мій досвід.
Брайан Вебстер

Зараз можливий безголовий хром. Я не знаю, чи швидше це, але якщо ви хочете точних знімків екрана, це хороший шлях.
Josh Maag

11

Ви можете використовувати інструмент HTML для PDF, наприклад wkhtmltopdf. І тоді ви можете використовувати PDF-файл для створення зображень, таких як imagemagick. Справді, це серверна сторона і дуже звичний процес ...


12
Або ви просто можете запустити зображення брата wkhtmltopdf, wkhtmltoimage.
Роман Старков

1
Ця бібліотека призначена для Node.js. Як щодо простого інтерфейсу?
Влад

9

Єдиною бібліотекою, з якою я працював для Chrome, Firefox та MS Edge, був rasterizeHTML . Він випускає кращу якість, ніж HTML2Canvas, і все ще підтримується на відміну від HTML2Canvas.

Отримання елемента та завантаження у форматі PNG

var node= document.getElementById("elementId");
var canvas = document.createElement("canvas");
canvas.height = node.offsetHeight;
canvas.width = node.offsetWidth;
var name = "test.png"

rasterizeHTML.drawHTML(node.outerHTML, canvas)
     .then(function (renderResult) {
            if (navigator.msSaveBlob) {
                window.navigator.msSaveBlob(canvas.msToBlob(), name);
            } else {
                const a = document.createElement("a");
                document.body.appendChild(a);
                a.style = "display: none";
                a.href = canvas.toDataURL();
                a.download = name;
                a.click();
                document.body.removeChild(a);
            }
     });


@vabanagas Чи є для цього якийсь один файловий javascript?
Махді Халілі

Ця зміна мені дуже допомогла: rasterizeHTML.drawHTML(node.innerHTML, canvas) Зауважте, що я дзвоню InternalHTML на вузол
вересень GH

5

Використовуйте html2canvas, просто включіть модуль плагіна та виклику для перетворення HTML у Canvas, а потім завантажте як зображення PNG

        html2canvas(document.getElementById("image-wrap")).then(function(canvas) {
            var link = document.createElement("a");
            document.body.appendChild(link);
            link.download = "manpower_efficiency.jpg";
            link.href = canvas.toDataURL();
            link.target = '_blank';
            link.click();
        });

Джерело : http://www.freakyjolly.com/convert-html-document-into-image-jpg-png-from-canvas/


4

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

Напишіть програму, яка відкриє ваш улюблений браузер до потрібного документа HTML, розмір вікна належним чином та знімок екрана. Потім видаліть межі зображення.


4

Використовуйте цей код, він обов'язково спрацює:

<script type="text/javascript">
 $(document).ready(function () {
	 setTimeout(function(){
		 downloadImage();
	 },1000)
 });
 
 function downloadImage(){
	 html2canvas(document.querySelector("#dvContainer")).then(canvas => {
		a = document.createElement('a'); 
		document.body.appendChild(a); 
		a.download = "test.png"; 
		a.href =  canvas.toDataURL();
		a.click();
	});	 
 }
</script>

Тільки не забудьте включити у свою програму файл Html2CanvasJS. https://html2canvas.hertzen.com/dist/html2canvas.js


2

Ви не можете це зробити 100% точно лише з JavaScript.

Там є інструмент Qt Webkit та версія python . Якщо ви хочете зробити це самостійно, я мав успіх з какао:

[self startTraverse:pagesArray performBlock:^(int collectionIndex, int pageIndex) {

    NSString *locale = [self selectedLocale];

    NSRect offscreenRect = NSMakeRect(0.0, 0.0, webView.frame.size.width, webView.frame.size.height);
    NSBitmapImageRep* offscreenRep = nil;      

    offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
                                             pixelsWide:offscreenRect.size.width
                                             pixelsHigh:offscreenRect.size.height
                                             bitsPerSample:8
                                             samplesPerPixel:4
                                             hasAlpha:YES
                                             isPlanar:NO
                                             colorSpaceName:NSCalibratedRGBColorSpace
                                             bitmapFormat:0
                                             bytesPerRow:(4 * offscreenRect.size.width)
                                             bitsPerPixel:32];

    [NSGraphicsContext saveGraphicsState];

    NSGraphicsContext *bitmapContext = [NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep];
    [NSGraphicsContext setCurrentContext:bitmapContext];
    [webView displayRectIgnoringOpacity:offscreenRect inContext:bitmapContext];
    [NSGraphicsContext restoreGraphicsState];

    // Create a small + large thumbs
    NSImage *smallThumbImage = [[NSImage alloc] initWithSize:thumbSizeSmall];  
    NSImage *largeThumbImage = [[NSImage alloc] initWithSize:thumbSizeLarge];

    [smallThumbImage lockFocus];
    [[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];  
    [offscreenRep drawInRect:CGRectMake(0, 0, thumbSizeSmall.width, thumbSizeSmall.height)];  
    NSBitmapImageRep *smallThumbOutput = [[NSBitmapImageRep alloc] initWithFocusedViewRect:CGRectMake(0, 0, thumbSizeSmall.width, thumbSizeSmall.height)];  
    [smallThumbImage unlockFocus];  

    [largeThumbImage lockFocus];  
    [[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];  
    [offscreenRep drawInRect:CGRectMake(0, 0, thumbSizeLarge.width, thumbSizeLarge.height)];  
    NSBitmapImageRep *largeThumbOutput = [[NSBitmapImageRep alloc] initWithFocusedViewRect:CGRectMake(0, 0, thumbSizeLarge.width, thumbSizeLarge.height)];  
    [largeThumbImage unlockFocus];  

    // Write out small
    NSString *writePathSmall = [issueProvider.imageDestinationPath stringByAppendingPathComponent:[NSString stringWithFormat:@"/%@-collection-%03d-page-%03d_small.png", locale, collectionIndex, pageIndex]];
    NSData *dataSmall = [smallThumbOutput representationUsingType:NSPNGFileType properties: nil];
    [dataSmall writeToFile:writePathSmall atomically: NO];

    // Write out lage
    NSString *writePathLarge = [issueProvider.imageDestinationPath stringByAppendingPathComponent:[NSString stringWithFormat:@"/%@-collection-%03d-page-%03d_large.png", locale, collectionIndex, pageIndex]];
    NSData *dataLarge = [largeThumbOutput representationUsingType:NSPNGFileType properties: nil];
    [dataLarge writeToFile:writePathLarge atomically: NO];
}];

Сподіваюся, це допомагає!


Чи є у вас швидка версія вищезазначеного? або, якщо можливо, можете, будь ласка, переписати його?
ssh

Ви б не хотіли поділитися кодом, який використовуєте для завантаження веб-перегляду, який ви надаєте? Це здається перспективним підходом для мого ескіза. Дякую!
Дейв

1

Встановіть phantomjs

$ npm install phantomjs

Створіть файл github.js із наступним кодом

var page = require('webpage').create();
//viewportSize being the actual size of the headless browser
page.viewportSize = { width: 1024, height: 768 };
page.open('http://github.com/', function() {
    page.render('github.png');
    phantom.exit();
});

Передайте файл як аргумент phantomjs

$ phantomjs github.js


-3

Ви можете додати до свого проекту посилання HtmlRenderer і зробити наступне,

string htmlCode ="<p>This is a sample html.</p>";
Image image = HtmlRender.RenderToImage(htmlCode ,new Size(500,300));
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.