Render HTML ke gambar


166

Apakah ada cara untuk merender html ke gambar seperti PNG? Saya tahu itu mungkin dengan kanvas tetapi saya ingin membuat elemen html standar seperti div misalnya.


Untuk membuat semacam bantuan pengguna, misalnya. Sayangnya, itu tidak mungkin (untuk alasan keamanan?). Anda harus meminta pengguna untuk menekan PrintScreen untuk melakukan sesuatu.
MaxArt


Saya ingin menggunakan HTML / CSS untuk mendesain logo.
Martin Delille

4
@ ErnestFriedman-Hill bukan duplikat: pertanyaan yang Anda sebutkan khusus untuk java.
Martin Delille

Berikut ini adalah tutorial Langkah demi Langkah untuk Mengubah HTML ke IMAGE png atau format jpeg codepedia.info/2016/02/...
Satinder singh

Jawaban:


41

Saya tahu ini adalah pertanyaan lama yang sudah memiliki banyak jawaban, namun saya masih menghabiskan waktu berjam-jam untuk benar-benar melakukan apa yang saya inginkan:

  • diberi file html, hasilkan gambar (png) dengan latar belakang transparan dari baris perintah

Menggunakan Chrome headless (versi 74.0.3729.157 pada respons ini), sebenarnya mudah:

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

Penjelasan perintah:

  • Anda menjalankan Chrome dari baris perintah (ditampilkan di sini untuk Mac, tetapi dengan asumsi serupa pada Windows atau Linux)
  • --headless menjalankan Chrome tanpa membukanya dan keluar setelah perintah selesai
  • --screenshotakan menangkap tangkapan layar (perhatikan bahwa itu menghasilkan file yang disebut screenshot.pngdi folder tempat perintah dijalankan)
  • --window-sizememungkinkan untuk hanya mengambil sebagian dari layar (formatnya --window-size=width,height)
  • --default-background-color=0adalah trik sulap yang memberi tahu Chrome untuk menggunakan latar belakang transparan , bukan warna putih default
  • akhirnya Anda memberikan file html (sebagai url baik lokal maupun jarak jauh ...)

1
Sangat bagus! Ia bekerja dengan SVG juga! Saya beralih ke solusi Anda pada akhirnya! ;-)
Martin Delille

1
--screenshot='absolute\path\of\screenshot.png'bekerja untuk saya
palash

garis komandan bekerja. jika saya ingin menjalankan ini secara programatik dari express js bagaimana menjalankannya?
Squapl Recipes

FYI ini juga berfungsi dengan kromium meskipun tidak menyebutkan opsi di halaman manual.
Robin Lashof-Regas

SVG bukan svg bagi saya ... itu hanya PNG dengan ekstensi SVG ... jadi hati-hati.
kristopolous

97

Iya. HTML2Canvas ada untuk merender HTML <canvas>(yang kemudian dapat Anda gunakan sebagai gambar).

CATATAN: Ada masalah yang diketahui, bahwa ini tidak akan berfungsi dengan SVG


Tampaknya menarik tetapi saya tidak berhasil membuatnya jadi saya memilih solusi John Fisher. Terima kasih atas informasinya, saya akan menonton proyek ini di masa depan!
Martin Delille

@ MartinDelille: di sini artikel menggunakan HTML2Canvas untuk membuat IMAGE dan Anda juga dapat mengunduhnya di sisi klien codepedia.info/2016/02/...
Satinder singh

3
dom-to-image (lihat jawaban tsayen) melakukan pekerjaan yang jauh lebih baik untuk membuat gambar yang akurat.
JBE

3
Solusi ini sangat lambat
hamboy75

3
masalah lain, jika elemen itu tersembunyi atau di belakang elemen lain ini tidak akan berfungsi
Yousef

91

Bolehkah saya merekomendasikan perpustakaan dom-ke-gambar , yang ditulis semata-mata untuk mengatasi masalah ini (saya pengelola).
Inilah cara Anda menggunakannya (beberapa lagi di sini ):

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
Ini bagus! Adakah cara untuk menggandakan ukuran output?
cronoklee

Terima kasih! Tapi apa sebenarnya yang Anda maksud dengan "menggandakan ukuran"?
tsayen

2
Hal pertama yang terlintas di pikiran saya - coba render gambar Anda ke SVG (menggunakan domtoimage.toSvg ), lalu render sendiri di atas kanvas dan cobalah untuk bermain dengan resolusi kanvas itu. Mungkin saja untuk mengimplementasikan fitur seperti semacam opsi rendering di lib itu sendiri, sehingga Anda dapat melewatkan dimensi gambar dalam piksel. Jika Anda membutuhkannya, saya menghargai Anda membuat masalah di github.
tsayen

8
Ini JAUH lebih baik daripada html2canvas. Terima kasih.
c.hughes

1
@ Subo itu adalah String yang berisi URL dengan data yang disandikan base64
tsayen

66

Ada banyak pilihan dan mereka semua memiliki pro dan kontra.

Opsi 1: Gunakan salah satu dari banyak perpustakaan yang tersedia

Pro

  • Konversi sebagian besar cukup cepat

Cons

  • Rendering yang buruk
  • Tidak menjalankan javascript
  • Tidak ada dukungan untuk fitur web terkini (FlexBox, Selectors Lanjutan, Webfonts, Ukuran Kotak, Kueri Media, ...)
  • Terkadang tidak begitu mudah untuk menginstal
  • Rumit dengan skala

Opsi 2: Gunakan PhantomJs dan mungkin pustaka pembungkus

Pro

  • Jalankan Javascript
  • Cukup cepat

Cons

  • Rendering yang buruk
  • Tidak ada dukungan untuk fitur web terkini (FlexBox, Selectors Lanjutan, Webfonts, Ukuran Kotak, Kueri Media, ...)
  • Rumit dengan skala
  • Tidak begitu mudah untuk membuatnya berfungsi jika ada gambar yang akan dimuat ...

Opsi 3: Gunakan Chrome Headless dan mungkin perpustakaan pembungkus

Pro

  • Jalankan Javascript
  • Render yang mendekati sempurna

Cons

  • Tidak begitu mudah mendapatkan hasil yang diinginkan mengenai:
    • waktu pemuatan halaman
    • dimensi viewport
  • Rumit dengan skala
  • Cukup lambat dan bahkan lebih lambat jika html berisi tautan eksternal

Opsi 4: Gunakan API

Pro

  • Jalankan Javascript
  • Render yang mendekati sempurna
  • Cepat saat opsi caching digunakan dengan benar
  • Skala ditangani oleh API
  • Waktu yang tepat, viewport, ...
  • Sebagian besar waktu mereka menawarkan paket gratis

Cons

  • Tidak gratis jika Anda berencana untuk sering menggunakannya

Disclosure: Saya adalah pendiri ApiFlash. Saya melakukan yang terbaik untuk memberikan jawaban yang jujur ​​dan bermanfaat.


2
Terima kasih atas jawaban terinci dengan banyak solusi yang memungkinkan
bszom

wkhtmltoimage / pdf mendukung rendering javascript. Anda dapat mengatur penundaan javascript atau biarkan wkhtml memeriksa window.status specifc (yang dapat Anda atur dengan javascript saat Anda tahu barang js Anda selesai)
Daniel Z.

PhantomJS mendukung hal-hal dinamis seperti Google Maps. Ini benar-benar browser web lengkap, hanya tanpa layar terpasang. Namun Anda harus menunggu sedikit agar Google Map memuat ubin dengan geografi (Saya menunggu 500ms dan memungkinkan orang untuk mengubah penundaan - jika itu tidak cukup, berjalan lagi tanpa menambah waktu baik-baik saja, karena ubin itu di-cache).
Ladislav Zima

50

Semua jawaban di sini menggunakan perpustakaan pihak ketiga saat merender HTML ke gambar bisa relatif sederhana dalam Javascript murni. Ada yang bahkan sebuah artikel tentang hal itu pada bagian kanvas di MDN.

Kuncinya adalah ini:

  • buat SVG dengan simpul foreignObject yang berisi XHTML Anda
  • atur src gambar ke url data SVG itu
  • drawImage ke atas kanvas
  • atur data kanvas ke target 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()
}

Beberapa hal yang perlu diperhatikan

  • HTML di dalam SVG haruslah XHTML
  • Demi alasan keamanan, SVG sebagai url data gambar berfungsi sebagai ruang lingkup CSS yang terisolasi untuk HTML karena tidak ada sumber eksternal yang dapat dimuat. Jadi font Google misalnya harus digarisbawahi menggunakan alat seperti ini .
  • Bahkan ketika HTML di dalam SVG melebihi ukuran gambar, ia akan menggambar ke kanvas dengan benar. Tetapi ketinggian sebenarnya tidak dapat diukur dari gambar itu. Solusi ketinggian tetap akan bekerja dengan baik tetapi ketinggian dinamis akan membutuhkan sedikit lebih banyak pekerjaan. Yang terbaik adalah merender data SVG menjadi iframe (untuk lingkup CSS terisolasi) dan menggunakan ukuran yang dihasilkan untuk kanvas.

Bagus! Menghapus ketergantungan perpustakaan eksternal memang cara yang baik untuk pergi. Saya mengubah jawaban yang saya terima :-)
Martin Delille

Artikel itu sudah tidak ada lagi.
MSC

2
Jawaban yang bagus, tetapi mengomentari keadaan seni HTML dan Web API, yang seperti biasa terlihat seperti sesuatu yang menarik seseorang di belakang - semua fungsionalitas ada secara teknis tetapi diekspos di belakang array (tanpa kata-kata dimaksudkan) dari jalur kode aneh yang menyerupai tidak ada kejelasan yang Anda harapkan dari API yang dirancang dengan baik. Dalam plainspeak: kemungkinan besar sepele untuk browser untuk memungkinkan Documentuntuk dirender menjadi raster (misalnya a Canvas), tetapi karena tidak ada yang peduli untuk membakukannya, kita harus menggunakan kegilaan seperti diilustrasikan di atas (jangan tersinggung oleh penulis ini) kode).
amn

1
Jawaban ini stackoverflow.com/questions/12637395/… sepertinya mengindikasikan Anda bisa melangkah terlalu jauh. Mozilla dan Chrome memiliki panjang data tak terbatas dan bahkan IE saat ini memungkinkan 4GB, yang bermuara di sekitar 3GB gambar (karena base64). Tetapi ini akan menjadi hal yang baik untuk diuji.
Sjeiti

3
- beberapa tes cepat dan kotor nanti - jsfiddle.net/Sjeiti/pcwudrmc/75965 Chrome, Edge dan Firefox naik ke ketinggian lebar setidaknya 10.000 piksel yang (dalam hal ini) adalah jumlah karakter sekitar 10.000.000 dan ukuran file png 8MB. Belum diuji dengan ketat tetapi cukup untuk sebagian besar kasus penggunaan.
Sjeiti

13

Anda bisa menggunakan PhantomJS , yang merupakan webkit tanpa kepala (mesin rendering di safari dan (hingga baru-baru ini) driver chrome). Anda dapat mempelajari cara melakukan tangkapan layar halaman di sini . Semoga itu bisa membantu!


Teknik ini bekerja dengan baik. Namun, 2 tahun telah berlalu sejak komentar Anda. Sudahkah Anda menemukan sesuatu yang beroperasi lebih cepat dari PhantomJS? Pembuatan Gambar biasanya memakan waktu 2-5 detik di Phantom, menurut pengalaman saya.
Brian Webster

Chrome tanpa kepala sekarang mungkin. Saya tidak tahu apakah ini lebih cepat, tetapi jika Anda ingin tangkapan layar yang akurat, ini adalah cara yang baik untuk melakukannya.
Josh Maag

11

Anda dapat menggunakan alat HTML ke PDF seperti wkhtmltopdf. Dan kemudian Anda dapat menggunakan alat PDF untuk gambar seperti imagemagick. Memang ini adalah sisi server dan proses yang sangat berbelit-belit ...


12
Atau Anda bisa menjalankan image saudara wkhtmltopdf, wkhtmltoimage.
Roman Starkov

1
Perpustakaan ini untuk Node.js. Bagaimana dengan frontend sederhana?
Vlad

9

Satu-satunya perpustakaan yang saya gunakan untuk Chrome, Firefox, dan MS Edge adalah rasterizeHTML . Ini menghasilkan kualitas yang lebih baik daripada HTML2Canvas dan masih didukung tidak seperti HTML2Canvas.

Mendapatkan Elemen dan Mengunduh sebagai 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);
            }
     });

2
tetapi tidak bekerja dengan IE. rasterizeHTML Batasan
Boban Stojanovski

@vabanagas apakah ada javascript file tunggal untuk ini?
Mahdi Khalili

Perubahan ini banyak membantu saya: rasterizeHTML.drawHTML(node.innerHTML, canvas) Perhatikan bahwa saya memanggil innerHTML pada node
Sep GH

5

Gunakan html2canvas cukup sertakan plugin dan metode panggilan untuk mengkonversi HTML ke Canvas kemudian unduh sebagai PNG gambar

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

Sumber : http://www.freakyjolly.com/convert-html-document-into-image-jpg-png-from-canvas/


4

Saya tidak berharap ini menjadi jawaban terbaik, tetapi sepertinya cukup menarik untuk dikirim.

Tulis aplikasi yang membuka browser favorit Anda ke dokumen HTML yang diinginkan, ukuran jendela dengan benar, dan mengambil screenshot. Kemudian, hapus batas gambar.


4

Gunakan kode ini, pasti akan bekerja:

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

Hanya saja, jangan lupa untuk memasukkan file Html2CanvasJS dalam program Anda. https://html2canvas.hertzen.com/dist/html2canvas.js


2

Anda tidak dapat melakukan ini 100% akurat hanya dengan JavaScript.

Ada alat Qt Webkit di luar sana, dan versi python . Jika Anda ingin melakukannya sendiri, saya sudah sukses dengan Cocoa:

[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];
}];

Semoga ini membantu!


Apakah Anda memiliki versi cepat di atas? atau jika mungkin bisakah Anda menulis ulang?
ssh

Maukah Anda berbagi kode yang Anda gunakan untuk memuat webView yang Anda render? Ini sepertinya pendekatan yang menjanjikan untuk penyaji thumbnail saya. Terima kasih!
Dave

1

Instal phantomjs

$ npm install phantomjs

Buat file github.js dengan kode berikut

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

Berikan file sebagai argumen ke phantomjs

$ phantomjs github.js


-3

Anda dapat menambahkan referensi HtmlRenderer ke proyek Anda dan melakukan hal berikut,

string htmlCode ="<p>This is a sample html.</p>";
Image image = HtmlRender.RenderToImage(htmlCode ,new Size(500,300));
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.