Kết xuất HTML thành hình ảnh


166

Có cách nào để kết xuất html thành hình ảnh như PNG không? Tôi biết rằng có thể với canvas nhưng tôi muốn kết xuất phần tử html tiêu chuẩn như div chẳng hạn.


Để tạo một số loại hỗ trợ người dùng, ví dụ. Đáng buồn thay, điều đó là không thể (vì lý do bảo mật?). Bạn phải yêu cầu người dùng nhấn PrintScreen để làm gì đó.
MaxArt


Tôi muốn sử dụng HTML / CSS để thiết kế logo.
Martin Delille

4
@ ErnestFriedman-Hill không trùng lặp: câu hỏi bạn đề cập là dành riêng cho java.
Martin Delille

Dưới đây là hướng dẫn từng bước để chuyển đổi HTML sang IMAGE định dạng png hoặc jpeg codepedia.info/2016/02/ mẹo
Satinder singh

Câu trả lời:


41

Tôi biết đây là một câu hỏi khá cũ đã có rất nhiều câu trả lời, nhưng tôi vẫn dành hàng giờ cố gắng để thực sự làm những gì tôi muốn:

  • đưa ra một tệp html, tạo một hình ảnh (png) với nền trong suốt từ dòng lệnh

Sử dụng Chrome không đầu (phiên bản 74.0.3729.157 cho phản hồi này), thực sự dễ dàng:

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

Giải thích về lệnh:

  • bạn chạy Chrome từ dòng lệnh (ở đây hiển thị cho Mac, nhưng giả sử tương tự trên Windows hoặc Linux)
  • --headless chạy Chrome mà không mở nó và thoát sau khi lệnh hoàn thành
  • --screenshot sẽ chụp ảnh màn hình (lưu ý rằng nó tạo ra một tệp có tên screenshot.png trong thư mục nơi lệnh được chạy)
  • --window-size chỉ cho phép chụp một phần màn hình (định dạng là --window-size=width,height )
  • --default-background-color=0là trò ảo thuật bảo Chrome sử dụng minh bạch nền chứ không phải màu trắng mặc định
  • cuối cùng bạn cung cấp tệp html (dưới dạng url hoặc cục bộ hoặc từ xa ...)

1
Rất đẹp! Nó cũng hoạt động với SVG! Tôi đã chuyển sang giải pháp của bạn cuối cùng! ;-)
Martin Delille

1
--screenshot='absolute\path\of\screenshot.png'làm việc cho tôi
palash

dòng comman làm việc. Nếu tôi muốn chạy chương trình này từ express js, làm thế nào để chạy nó?
Bí quyết Squapl

FYI này cũng hoạt động với crom mặc dù nó không đề cập đến tùy chọn trong trang người đàn ông.
Robin Lashof-Regas

Svg không phải là một Svg đối với tôi ... nó chỉ là một PNG có phần mở rộng SVG ... vì vậy hãy coi chừng.
kristopolous

97

Đúng. HTML2Canvas tồn tại để hiển thị HTML lên<canvas> (mà sau đó bạn có thể sử dụng làm hình ảnh).

LƯU Ý: Có một vấn đề đã biết, điều này sẽ không hoạt động với SVG


Có vẻ thú vị nhưng tôi đã không quản lý để làm cho nó hoạt động nên tôi chọn giải pháp John Fisher. Cảm ơn thông tin, tôi sẽ xem dự án này trong tương lai!
Martin Delille

@MartinDelille: đây là một bài viết về việc sử dụng HTML2Canvas để tạo IMAGE và bạn cũng có thể tải xuống tại codepedia.info/2016 / 02/2016
Satinder singh 19/2/2016

3
dom-to-image (xem câu trả lời của tsayen) thực hiện công việc tốt hơn nhiều để hiển thị một bức tranh chính xác.
JBE

3
Giải pháp này rất chậm
hamboy75

3
một vấn đề khác, nếu phần tử bị ẩn hoặc đằng sau phần tử khác thì phần tử này sẽ không hoạt động
Yousef

91

Tôi có thể giới thiệu thư viện dom-to-image , được viết riêng để giải quyết vấn đề này (Tôi là người bảo trì).
Đây là cách bạn sử dụng nó (một số chi tiết ở đây ):

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
Điều đó thật tuyệt! Bất kỳ cách nào để tăng gấp đôi kích thước đầu ra?
cronoklee

Cảm ơn! Nhưng chính xác ý bạn là gì khi "nhân đôi kích thước"?
tsayen

2
Điều đầu tiên tôi nghĩ đến - hãy thử kết xuất hình ảnh của bạn thành SVG (sử dụng domtoimage.toSvg), sau đó tự hiển thị nó trên khung vẽ và cố gắng chơi với độ phân giải của khung vẽ đó bằng cách nào đó. Có thể thực hiện tính năng này như một số loại tùy chọn kết xuất trong chính lib, vì vậy bạn có thể chuyển kích thước hình ảnh bằng pixel. Nếu bạn cần nó, tôi đánh giá cao việc bạn tạo ra một vấn đề trên github.
tsayen

8
Điều này là tốt hơn so với html2canvas. Cảm ơn.
c.hughes

1
@Subho đó là Chuỗi chứa URL với dữ liệu được mã hóa base64
tsayen

66

Có rất nhiều lựa chọn và tất cả đều có ưu và nhược điểm của họ.

Tùy chọn 1: Sử dụng một trong nhiều thư viện có sẵn

Ưu

  • Chuyển đổi khá nhanh hầu hết thời gian

Nhược điểm

  • Kết xuất xấu
  • Không thực thi javascript
  • Không hỗ trợ cho các tính năng web gần đây (FlexBox, Bộ chọn nâng cao, Webfont, Định cỡ hộp, Truy vấn phương tiện, ...)
  • Đôi khi không dễ cài đặt
  • Biến chứng

Tùy chọn 2: Sử dụng PhantomJs và có thể là thư viện trình bao bọc

Ưu

  • Thực thi Javascript
  • Khá nhanh

Nhược điểm

  • Kết xuất xấu
  • Không hỗ trợ cho các tính năng web gần đây (FlexBox, Bộ chọn nâng cao, Webfont, Định cỡ hộp, Truy vấn phương tiện, ...)
  • Biến chứng
  • Không dễ để làm cho nó hoạt động nếu có hình ảnh được tải ...

Tùy chọn 3: Sử dụng Chrome Headless và có thể là thư viện trình bao bọc

Ưu

  • Thực thi Javascript
  • Kết xuất gần hoàn hảo

Nhược điểm

  • Không dễ để có chính xác kết quả mong muốn liên quan đến:
    • thời gian tải trang
    • kích thước khung nhìn
  • Biến chứng
  • Khá chậm và thậm chí chậm hơn nếu html chứa các liên kết bên ngoài

Tùy chọn 4: Sử dụng API

Ưu

  • Thực thi Javascript
  • Kết xuất gần hoàn hảo
  • Nhanh khi các tùy chọn bộ nhớ đệm được sử dụng chính xác
  • Tỷ lệ được xử lý bởi các API
  • Thời gian chính xác, chế độ xem, ...
  • Hầu hết thời gian họ cung cấp một gói miễn phí

Nhược điểm

  • Không miễn phí nếu bạn có kế hoạch sử dụng chúng nhiều

Tiết lộ: Tôi là người sáng lập ApiFlash. Tôi đã làm hết sức mình để cung cấp một câu trả lời trung thực và hữu ích.


2
Cảm ơn bạn đã trả lời chi tiết với rất nhiều giải pháp khả thi
bszom 26/03/18

wkhtmltoimage / pdf không hỗ trợ kết xuất javascript. Bạn có thể thiết lập một sự chậm trễ javascript hoặc để kiểm tra wkhtml cho một window.status specifc (mà bạn có thể thiết lập với javascript khi bạn biết công cụ js của bạn được thực hiện)
Daniel Z.

PhantomJS hỗ trợ các công cụ năng động như Google Maps. Đây thực sự là một trình duyệt web đầy đủ, chỉ cần không có màn hình đính kèm. Tuy nhiên, bạn phải đợi một chút để Google Map tải các ô theo địa lý (tôi đợi 500ms và cho phép mọi người thay đổi độ trễ - nếu không đủ, chạy lại mà không tăng thời gian là tốt, vì các ô đó được lưu trong bộ nhớ cache).
Ladislav Zima

50

Tất cả các câu trả lời ở đây sử dụng thư viện của bên thứ ba trong khi hiển thị HTML thành hình ảnh có thể tương đối đơn giản trong Javascript thuần túy. Có được thậm chí còn một bài viết về nó trên phần vải trên MDN.

Bí quyết là thế này:

  • tạo một SVG với nút ForeignObject chứa XHTML của bạn
  • đặt src của hình ảnh thành url dữ liệu của SVG đó
  • drawImage lên tấm bạt
  • đặt dữ liệu canvas vào mục tiêu 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()
}

Một số điều cần lưu ý

  • HTML bên trong SVG phải là XHTML
  • Vì lý do bảo mật, SVG là url dữ liệu của hình ảnh hoạt động như một phạm vi CSS bị cô lập cho HTML do không có nguồn bên ngoài nào có thể được tải. Vì vậy, một phông chữ Google chẳng hạn phải được nội tuyến bằng một công cụ như thế này .
  • Ngay cả khi HTML bên trong SVG vượt quá kích thước của hình ảnh, nó sẽ vẽ chính xác lên khung vẽ. Nhưng chiều cao thực tế không thể đo được từ hình ảnh đó. Một giải pháp chiều cao cố định sẽ hoạt động tốt nhưng chiều cao động sẽ đòi hỏi công việc nhiều hơn một chút. Cách tốt nhất là kết xuất dữ liệu SVG thành iframe (đối với phạm vi CSS bị cô lập) và sử dụng kích thước kết quả cho khung vẽ.

Đẹp! Loại bỏ sự phụ thuộc thư viện bên ngoài thực sự là cách tốt để đi. Tôi đã thay đổi câu trả lời được chấp nhận của mình :-)
Martin Delille

Bài báo đó không còn nữa.
MSC

2
Câu trả lời tuyệt vời, nhưng nhận xét về trạng thái nghệ thuật của HTML và API Web, như thường lệ trông giống như có thứ gì đó rút ra phía sau - tất cả các chức năng đều có ở đó nhưng lộ ra đằng sau một mảng (không có ý định chơi chữ) của các đường dẫn mã kỳ lạ giống với không có gì rõ ràng mà bạn mong đợi từ các API được thiết kế tốt. Nói một cách dễ hiểu: rất có thể là một trình duyệt không cho phép Documentkết xuất thành raster (ví dụ a Canvas), nhưng vì không ai bận tâm đến việc chuẩn hóa nó, chúng tôi phải dùng đến sự điên rồ như minh họa ở trên (không có ý xúc phạm đối với tác giả này mã).
amn

1
Câu trả lời này stackoverflow.com/questions/12637395/ dường như cho thấy bạn có thể đi khá xa. Mozilla và Chrome có dữ liệu không giới hạn và thậm chí IE hiện tại cho phép 4GB, có thể giảm xuống còn khoảng 3 GB hình ảnh (do Base64). Nhưng đây sẽ là một điều tốt để kiểm tra.
Sjeiti

3
- một số thử nghiệm nhanh và bẩn sau này - jsfiddle.net/Sjeiti/pcwudrmc/75965 Chrome, Edge và Firefox có chiều cao tối thiểu 10.000 pixel (trong trường hợp này) là số lượng ký tự khoảng 10.000.000 và kích thước tệp png 8 MB. Không được kiểm tra nghiêm ngặt nhưng nó đủ cho hầu hết các trường hợp sử dụng.
Sjeiti

13

Bạn có thể sử dụng PhantomJS , đây là một webkit không đầu (công cụ kết xuất trong safari và trình điều khiển chrome (cho đến gần đây). Bạn có thể tìm hiểu làm thế nào để chụp màn hình các trang ở đây . Mong rằng sẽ giúp!


Kỹ thuật này hoạt động tốt. Tuy nhiên, đã 2 năm trôi qua kể từ bình luận của bạn. Bạn đã bắt gặp bất cứ thứ gì hoạt động nhanh hơn PhantomJS chưa? Thế hệ hình ảnh thường mất 2-5 giây trong Phantom, theo kinh nghiệm của tôi.
Brian Webster

Chrome không đầu giờ đã có thể. Tôi không biết nếu nó nhanh hơn, nhưng nếu bạn muốn chụp ảnh màn hình chính xác, đây là một cách tốt để đi.
Josh Maag

11

Bạn có thể sử dụng công cụ HTML sang PDF như wkhtmltopdf. Và sau đó bạn có thể sử dụng một công cụ PDF thành hình ảnh như hình ảnh. Phải thừa nhận rằng đây là phía máy chủ và một quy trình rất phức tạp ...


12
Hoặc bạn chỉ có thể chạy hình ảnh anh em của wkhtmltopdf, wkhtmltoimage.
Roman Starkov

1
Thư viện này là dành cho Node.js. Làm thế nào về frontend đơn giản?
Vlad

9

Thư viện duy nhất tôi có thể làm việc cho Chrome, Firefox và MS Edge là rasterizeHTML . Nó cho ra chất lượng tốt hơn HTML2Canvas và vẫn được hỗ trợ không giống như HTML2Canvas.

Lấy phần tử và tải xuống dưới dạng 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
nhưng nó không hoạt động với IE. rasterizeHTML Hạn chế
Boban Stojanovski

@vabanagas có tập tin javascript nào cho việc này không?
Mahdi Khalili

Thay đổi này đã giúp tôi rất nhiều: rasterizeHTML.drawHTML(node.innerHTML, canvas) Lưu ý rằng tôi đang gọi InternalHTML trên nút
Sep GH

5

Sử dụng html2canvas chỉ bao gồm plugin và phương thức gọi để chuyển đổi HTML sang Canvas sau đó tải xuống dưới dạng hình ảnh 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();
        });

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


4

Tôi không hy vọng đây sẽ là câu trả lời hay nhất, nhưng nó có vẻ đủ thú vị để đăng.

Viết một ứng dụng mở trình duyệt yêu thích của bạn vào tài liệu HTML mong muốn, kích thước cửa sổ chính xác và chụp ảnh màn hình. Sau đó, loại bỏ các đường viền của hình ảnh.


4

Sử dụng mã này, nó chắc chắn sẽ hoạt động:

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

Chỉ cần đừng quên bao gồm tệp Html2CanvasJS trong chương trình của bạn. https://html2canvas.hertzen.com/dist/html2canvas.js


2

Bạn không thể làm điều này chính xác 100% chỉ với JavaScript.

Có một công cụ Qt Webkit ngoài đó và một phiên bản python . Nếu bạn muốn tự làm, tôi đã thành công với ca cao:

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

Hi vọng điêu nay co ich!


Bạn có phiên bản nhanh chóng ở trên? hoặc nếu có thể bạn có thể vui lòng viết lại nó?
ssh

Bạn có muốn chia sẻ mã bạn sử dụng để tải webView mà bạn đang kết xuất không? Đây có vẻ như là một cách tiếp cận đầy hứa hẹn cho trình kết xuất hình thu nhỏ của tôi. Cảm ơn!
Dave

1

Cài đặt ph Phantomjs

$ npm install phantomjs

Tạo một tệp github.js với mã sau

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

Truyền tệp dưới dạng đối số cho ph Phantomjs

$ phantomjs github.js


-3

Bạn có thể thêm tham chiếu HtmlRenderer vào dự án của bạn và làm như sau,

string htmlCode ="<p>This is a sample html.</p>";
Image image = HtmlRender.RenderToImage(htmlCode ,new Size(500,300));
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.