HTML을 이미지로 렌더링


167

PNG와 같이 HTML을 이미지로 렌더링하는 방법이 있습니까? 캔버스에서 가능하다는 것을 알고 있지만 예를 들어 div와 같은 표준 HTML 요소를 렌더링하고 싶습니다.


예를 들어 일종의 사용자 지원을 작성합니다. 안타깝게도 보안상의 이유로 불가능합니다. 무언가를하려면 PrintScreen을 누르라고 사용자에게 요청해야합니다.
MaxArt


HTML / CSS를 사용하여 로고를 디자인하고 싶습니다.
Martin Delille 2016 년

4
@ ErnestFriedman-Hill은 중복되지 않습니다. 언급 한 질문은 java에만 해당됩니다.
Martin Delille 2016 년

다음은 HTML을 이미지로 변환하기위한 단계별 튜토리얼입니다 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=0Chrome에 기본 흰색이 아닌 투명한 배경 을 사용하도록 지시하는 마술
  • 마지막으로 html 파일을 제공합니다 (로컬 또는 원격 URL로).

1
아주 좋아요! SVG에서도 작동합니다! 나는 결국 당신의 솔루션으로 전환했습니다! ;-)
Martin Delille

1
--screenshot='absolute\path\of\screenshot.png'나를 위해 일했다
palash

comman 라인이 작동했습니다. Express js에서 프로그래밍 방식으로 실행하려면 어떻게 실행합니까?
쿼플 레시피

참고로 맨 페이지의 옵션을 언급하지 않아도 크롬과 함께 작동합니다.
Robin Lashof-Regas

svg는 svg가 아닙니다 ... SVG 확장자를 가진 PNG 일뿐입니다 ... 조심하십시오.
kristopolous

97

예. HTML2Canvas 는 HTML을 렌더링하기 위해 존재합니다 <canvas>(이미지로 사용할 수 있음).

참고 : SVG에서는 작동하지 않는 알려진 문제가 있습니다.


흥미로운 것 같지만 작동하지 않아서 John Fisher 솔루션을 선택했습니다. 정보 주셔서 감사합니다, 나는이 프로젝트를 나중에 볼 수 있습니다!
Martin Delille 2016 년

@MartinDelille : 여기에 HTML2Canvas를 사용하여 이미지를 만드는 기사가 있으며 클라이언트 쪽 codepedia.info/2016/02/…
Satinder singh

3
dom-to-image (tsayen의 답변 참조)는 정확한 그림을 렌더링하는 데 훨씬 더 나은 작업을 수행합니다.
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 2016 년

1
@Subho base64로 인코딩 된 데이터가있는 URL을 포함하는 문자열입니다
tsayen

66

많은 옵션이 있으며 모두 장단점이 있습니다.

옵션 1 : 사용 가능한 많은 라이브러리 중 하나 사용

찬성

  • 대부분의 경우 변환은 매우 빠릅니다.

단점

  • 잘못된 렌더링
  • 자바 스크립트를 실행하지 않습니다
  • 최근 웹 기능 (FlexBox, 고급 선택기, 웹 폰트, 상자 크기 조정, 미디어 쿼리 등)은 지원하지 않습니다.
  • 때로는 설치가 쉽지 않은 경우가 있습니다
  • 규모가 복잡하다

옵션 2 : PhantomJ 및 랩퍼 라이브러리 사용

찬성

  • 자바 스크립트 실행
  • 꽤 빠른

단점

  • 잘못된 렌더링
  • 최근 웹 기능 (FlexBox, 고급 선택기, 웹 폰트, 상자 크기 조정, 미디어 쿼리 등)은 지원하지 않습니다.
  • 규모가 복잡하다
  • 로드 할 이미지가있는 경우 작동하기가 쉽지 않습니다 ...

옵션 3 : Chrome 헤드리스 및 랩퍼 라이브러리 사용

찬성

  • 자바 스크립트 실행
  • 거의 완벽한 렌더링

단점

  • 다음과 관련하여 원하는 결과를 정확하게 얻는 것은 쉽지 않습니다.
    • 페이지로드 타이밍
    • 뷰포트 치수
  • 규모가 복잡하다
  • HTML에 외부 링크가 포함되어 있으면 상당히 느리고 느려집니다.

옵션 4 : API 사용

찬성

  • 자바 스크립트 실행
  • 거의 완벽한 렌더링
  • 캐싱 옵션을 올바르게 사용할 때 빠름
  • 스케일은 API에 의해 처리됩니다
  • 정확한 타이밍, 뷰포트, ...
  • 대부분의 경우 무료 플랜을 제공합니다

단점

  • 많이 사용할 계획이라면 무료가 아닙니다.

공개 : 저는 ApiFlash의 창립자입니다. 나는 정직하고 유용한 답변을 제공하기 위해 최선을 다했습니다.


2
가능한 해결책이 많이있는 자세한 답변에 감사드립니다
bszom

wkhtmltoimage / pdf는 자바 스크립트 렌더링을 지원합니다. 자바 스크립트 지연을 설정하거나 wkhtml이 특정 window.status를 검사하도록 할 수 있습니다 (Js 작업이 완료된 것을 알 때 자바 스크립트로 설정할 수 있음)
Daniel Z.

PhantomJS는 Google지도와 같은 동적 기능을 지원합니다. 디스플레이가 연결되지 않은 완전한 웹 브라우저입니다. 그러나 Google Map이 지리와 함께 타일을로드 할 때까지 조금 기다려야합니다 (500ms 기다린 후 사람들이 지연을 변경할 수 있습니다-충분하지 않으면 시간을 늘리지 않고 다시 실행하면 타일이 캐시되기 때문에 괜찮습니다).
Ladislav Zima

50

여기에있는 모든 답변은 타사 라이브러리를 사용하는 반면 HTML을 이미지로 렌더링하는 것은 순수한 Javascript에서 비교적 간단 할 수 있습니다. 가 되고 도 있었다 그것에 대해 기사 MDN에 캔버스 섹션은.

요령은 다음과 같습니다.

  • XHTML을 포함하는 foreignObject 노드로 SVG를 만듭니다.
  • 이미지의 src를 해당 SVG의 데이터 URL로 설정하십시오.
  • drawImage 캔버스에
  • 캔버스 데이터를 대상 이미지로 설정하십시오.

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

몇 가지 참고할 사항

  • SVG 내부의 HTML은 XHTML이어야합니다
  • 보안상의 이유로 이미지의 데이터 URL 인 SVG는 외부 소스를로드 할 수 없으므로 HTML에 대한 격리 된 CSS 범위로 작동합니다. 그래서 예를 들어 구글 글꼴 같은 도구를 사용하여 인라인해야하는 이 일을 .
  • SVG 내부의 HTML이 이미지의 크기를 초과하더라도 캔버스에 올바르게 그려집니다. 그러나 실제 높이는 해당 이미지에서 측정 할 수 없습니다. 고정 높이 솔루션은 잘 작동하지만 동적 높이는 약간 더 많은 작업이 필요합니다. SVG 데이터를 격리 된 CSS 범위의 경우 iframe으로 렌더링하고 결과 크기를 캔버스에 사용하는 것이 가장 좋습니다.

좋은! 외부 라이브러리 종속성을 제거하는 것이 실제로 좋은 방법입니다. 나는 나의 대답을 바꾸었다 :-)
Martin Delille

그 기사는 더 이상 존재하지 않습니다.
MSC

2
대단한 대답이지만 HTML 및 웹 API의 최신 상태에 대해 언급하면 ​​평소와 같이 누군가를 끌어 낸 것처럼 보입니다. 모든 기능은 기술적으로 있지만 펑크 한 코드 경로와 유사한 배열 뒤에 숨겨져 있습니다. 잘 설계된 API에서 기대할 수있는 명확성은 없습니다. 간단히 말해서 : 브라우저가 a Document를 래스터 (예 :) 로 렌더링 하는 것은 사소한 Canvas일이지만, 아무도 표준화를 귀찮게하지 않기 때문에 위에서 설명한 것처럼 광기에 의존해야합니다. 암호).
amn

1
이 답변 stackoverflow.com/questions/12637395/… 당신이 아주 멀리 갈 수 있음을 나타내는 것 같습니다. 모질라와 크롬은 데이터 길이에 제한이 없으며 현재 IE에서도 4GB를 허용하며, 이는 base64로 인해 약 3GB 이미지로 줄어 듭니다. 그러나 이것은 테스트하기 좋은 것입니다.
Sjeiti

3
-나중에 빠르고 더러운 테스트 -jsfiddle.net/Sjeiti/pcwudrmc/75965 Chrome, Edge 및 Firefox는 너비가 최소 10,000 픽셀 (이 경우)의 문자 수는 약 10,000,000이고 PNG 파일 크기는 최대 10,000 픽셀입니다. 8MB 엄격하게 테스트하지는 않았지만 대부분의 사용 사례에 충분합니다.
Sjeiti

13

헤드리스 웹킷 (사파리의 렌더링 엔진 및 (최근까지) 크롬) 드라이버 인 PhantomJS를 사용할 수 있습니다 . 여기 에서 페이지의 화면 캡처 방법을 배울 수 있습니다 . 희망이 도움이됩니다!


이 기술은 잘 작동합니다. 그러나 귀하의 의견 이후 2 년이 지났습니다. PhantomJS보다 빠르게 작동하는 것을 발견하셨습니까? 필자의 경험으로는 Phantom에서 이미지 생성에 일반적으로 2-5 초가 걸립니다.
Brian Webster

헤드리스 크롬이 가능해졌습니다. 더 빠른지 모르겠지만 정확한 스크린 샷을 원한다면 좋은 방법입니다.
Josh Maag

11

wkhtmltopdf와 같은 HTML-PDF 도구를 사용할 수 있습니다. 그런 다음 PDF를 사용하여 imagemagick와 같은 이미지 도구를 사용할 수 있습니다. 분명히 이것은 서버 측이며 매우 복잡한 프로세스입니다 ...


12
또는 wkhtmltopdf의 이미지 형제 인 wkhtmltoimage를 실행할 수도 있습니다.
Roman Starkov

1
이 라이브러리는입니다 Node.js. 간단한 프론트 엔드는 어떻습니까?
Vlad

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

2
그러나 IE에서는 작동하지 않습니다. rasterizeHTML 제한
Boban Stojanovski

@vabanagas 이것에 대한 단일 파일 자바 스크립트가 있습니까?
Mahdi Khalili

이 변경 사항은 많은 도움이 rasterizeHTML.drawHTML(node.innerHTML, canvas) 되었습니다. 노드에서 innerHTML을 호출하는 Im
Sep 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

JavaScript만으로는 100 % 정확하게이 작업을 수행 할 수 없습니다.

Qt 웹 키트 도구파이썬 버전이 있습니다. 직접하고 싶다면 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];
}];

도움이 되었기를 바랍니다!


위의 빠른 버전이 있습니까? 아니면 가능하다면 다시 쓰시겠습니까?
ssh

렌더링중인 webView를로드하는 데 사용하는 코드를 공유 하시겠습니까? 이것은 썸네일 렌더러에 대한 유망한 접근법처럼 보입니다. 감사!
Dave

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));
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.