Google의 "버그 신고"또는 "피드백 도구"를 사용하면 브라우저 창의 영역을 선택하여 버그에 대한 피드백과 함께 제출 된 스크린 샷을 만들 수 있습니다.
Jason Small의 스크린 샷은 중복 질문으로 게시되었습니다 .
그들은 이것을 어떻게하고 있습니까? 구글의 자바 스크립트 피드백 API가에서로드 여기 및 피드백 모듈의 자신의 개요는 스크린 샷 기능을 시연 할 예정이다.
Google의 "버그 신고"또는 "피드백 도구"를 사용하면 브라우저 창의 영역을 선택하여 버그에 대한 피드백과 함께 제출 된 스크린 샷을 만들 수 있습니다.
Jason Small의 스크린 샷은 중복 질문으로 게시되었습니다 .
그들은 이것을 어떻게하고 있습니까? 구글의 자바 스크립트 피드백 API가에서로드 여기 및 피드백 모듈의 자신의 개요는 스크린 샷 기능을 시연 할 예정이다.
답변:
JavaScript는 DOM을 읽고를 사용하여 DOM을 상당히 정확하게 표현할 수 canvas
있습니다. HTML을 캔버스 이미지로 변환하는 스크립트를 작성했습니다. 설명 된대로 피드백을 보내도록 구현하기로 결정했습니다.
이 스크립트를 사용하면 클라이언트 브라우저에서 만든 스크린 샷과 함께 피드백 양식을 양식과 함께 만들 수 있습니다. 스크린 샷은 DOM을 기반으로하므로 실제 스크린 샷을 만들지 않으므로 페이지에 제공되는 정보를 기반으로 스크린 샷을 작성하므로 실제 표현에 100 % 정확하지 않을 수 있습니다.
그것은 서버에서 모든 렌더링을 필요로하지 않습니다 전체 이미지가 클라이언트의 브라우저에 생성 될 때,. HTML2Canvas 스크립트 자체는 여전히 매우 실험적인 상태에 있습니다. 필요한 CSS3 속성을 거의 구문 분석하지 않으며 프록시를 사용할 수 있어도 CORS 이미지를로드 할 수 없습니다.
브라우저 호환성은 여전히 제한적입니다 (더 많은 것을 지원할 수 없었기 때문에 더 많은 브라우저를 지원할 시간이 없었습니다).
자세한 내용은 다음 예제를 참조하십시오.
http://hertzen.com/experiments/jsfeedback/
편집 html2canvas 스크립트를 별도로 사용할 수 있습니다 여기에 몇 가지 여기 예 .
편집 2 Google이 매우 유사한 방법을 사용한다는 또 다른 확인 (사실, 문서를 기반으로 한 유일한 차이점은 트래버스 / 그리기의 비동기 방법뿐 임)이 Google 피드백 팀의 Elliott Sprehn이 프레젠테이션에서 찾을 수 있습니다. http : //www.elliottsprehn.com/preso/fluentconf/
웹 앱은 이제 다음을 사용하여 클라이언트 전체 데스크톱의 '기본'스크린 샷을 만들 수 있습니다 getUserMedia()
.
이 예를 살펴보십시오.
https://www.webrtc-experiment.com/Pluginfree-Screen-Sharing/
클라이언트는 현재 크롬을 사용해야하고 chrome : // flags에서 화면 캡처 지원을 활성화해야합니다.
Navigator.getUserMedia()
은 더 이상 사용되지 않지만 바로 아래에 "...라는 최신 navigator.mediaDevices.getUserMedia () "를 사용하십시오 . 즉, 새로운 API로 대체되었습니다.
으로 니클라스 언급 당신은 사용할 수 있습니다 html2canvas의 브라우저에서 JS를 사용하여 스크린 샷을 라이브러리를. 이 라이브러리를 사용하여 스크린 샷을 찍는 예를 제공 하여이 시점에서 그의 대답을 확장 할 것입니다.
에서 report()
함수 onrendered
데이터 URI로 이미지를 얻기 후에는 사용자에게 보여 그를 마우스로 "버그 영역을"그릴 다음 서버에 스크린 샷 및 지역 좌표를 보낼 수 있습니다.
이 예제 에서는 async/await
버전 : with nice makeScreenshot()
function 이 만들어졌습니다 .
스크린 샷을 찍고, 지역을 선택하고, 버그를 설명하고 POST 요청 ( 여기서는 jsfiddle )을 보낼 수있는 간단한 예입니다 (주 함수는 report()
).
getDisplayMedia API를 사용하여 스크린 샷을 Canvas 또는 Jpeg Blob / ArrayBuffer로 가져옵니다 .
// docs: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia
// see: https://www.webrtc-experiment.com/Pluginfree-Screen-Sharing/#20893521368186473
// see: https://github.com/muaz-khan/WebRTC-Experiment/blob/master/Pluginfree-Screen-Sharing/conference.js
function getDisplayMedia(options) {
if (navigator.mediaDevices && navigator.mediaDevices.getDisplayMedia) {
return navigator.mediaDevices.getDisplayMedia(options)
}
if (navigator.getDisplayMedia) {
return navigator.getDisplayMedia(options)
}
if (navigator.webkitGetDisplayMedia) {
return navigator.webkitGetDisplayMedia(options)
}
if (navigator.mozGetDisplayMedia) {
return navigator.mozGetDisplayMedia(options)
}
throw new Error('getDisplayMedia is not defined')
}
function getUserMedia(options) {
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
return navigator.mediaDevices.getUserMedia(options)
}
if (navigator.getUserMedia) {
return navigator.getUserMedia(options)
}
if (navigator.webkitGetUserMedia) {
return navigator.webkitGetUserMedia(options)
}
if (navigator.mozGetUserMedia) {
return navigator.mozGetUserMedia(options)
}
throw new Error('getUserMedia is not defined')
}
async function takeScreenshotStream() {
// see: https://developer.mozilla.org/en-US/docs/Web/API/Window/screen
const width = screen.width * (window.devicePixelRatio || 1)
const height = screen.height * (window.devicePixelRatio || 1)
const errors = []
let stream
try {
stream = await getDisplayMedia({
audio: false,
// see: https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamConstraints/video
video: {
width,
height,
frameRate: 1,
},
})
} catch (ex) {
errors.push(ex)
}
try {
// for electron js
stream = await getUserMedia({
audio: false,
video: {
mandatory: {
chromeMediaSource: 'desktop',
// chromeMediaSourceId: source.id,
minWidth : width,
maxWidth : width,
minHeight : height,
maxHeight : height,
},
},
})
} catch (ex) {
errors.push(ex)
}
if (errors.length) {
console.debug(...errors)
}
return stream
}
async function takeScreenshotCanvas() {
const stream = await takeScreenshotStream()
if (!stream) {
return null
}
// from: https://stackoverflow.com/a/57665309/5221762
const video = document.createElement('video')
const result = await new Promise((resolve, reject) => {
video.onloadedmetadata = () => {
video.play()
video.pause()
// from: https://github.com/kasprownik/electron-screencapture/blob/master/index.js
const canvas = document.createElement('canvas')
canvas.width = video.videoWidth
canvas.height = video.videoHeight
const context = canvas.getContext('2d')
// see: https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement
context.drawImage(video, 0, 0, video.videoWidth, video.videoHeight)
resolve(canvas)
}
video.srcObject = stream
})
stream.getTracks().forEach(function (track) {
track.stop()
})
return result
}
// from: https://stackoverflow.com/a/46182044/5221762
function getJpegBlob(canvas) {
return new Promise((resolve, reject) => {
// docs: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob
canvas.toBlob(blob => resolve(blob), 'image/jpeg', 0.95)
})
}
async function getJpegBytes(canvas) {
const blob = await getJpegBlob(canvas)
return new Promise((resolve, reject) => {
const fileReader = new FileReader()
fileReader.addEventListener('loadend', function () {
if (this.error) {
reject(this.error)
return
}
resolve(this.result)
})
fileReader.readAsArrayBuffer(blob)
})
}
async function takeScreenshotJpegBlob() {
const canvas = await takeScreenshotCanvas()
if (!canvas) {
return null
}
return getJpegBlob(canvas)
}
async function takeScreenshotJpegBytes() {
const canvas = await takeScreenshotCanvas()
if (!canvas) {
return null
}
return getJpegBytes(canvas)
}
function blobToCanvas(blob, maxWidth, maxHeight) {
return new Promise((resolve, reject) => {
const img = new Image()
img.onload = function () {
const canvas = document.createElement('canvas')
const scale = Math.min(
1,
maxWidth ? maxWidth / img.width : 1,
maxHeight ? maxHeight / img.height : 1,
)
canvas.width = img.width * scale
canvas.height = img.height * scale
const ctx = canvas.getContext('2d')
ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height)
resolve(canvas)
}
img.onerror = () => {
reject(new Error('Error load blob to Image'))
}
img.src = URL.createObjectURL(blob)
})
}
데모:
// take the screenshot
var screenshotJpegBlob = await takeScreenshotJpegBlob()
// show preview with max size 300 x 300 px
var previewCanvas = await blobToCanvas(screenshotJpegBlob, 300, 300)
previewCanvas.style.position = 'fixed'
document.body.appendChild(previewCanvas)
// send it to the server
let formdata = new FormData()
formdata.append("screenshot", screenshotJpegBlob)
await fetch('https://your-web-site.com/', {
method: 'POST',
body: formdata,
'Content-Type' : "multipart/form-data",
})
다음은 getDisplayMedia 를 사용하는 예입니다.
document.body.innerHTML = '<video style="width: 100%; height: 100%; border: 1px black solid;"/>';
navigator.mediaDevices.getDisplayMedia()
.then( mediaStream => {
const video = document.querySelector('video');
video.srcObject = mediaStream;
video.onloadedmetadata = e => {
video.play();
video.pause();
};
})
.catch( err => console.log(`${err.name}: ${err.message}`));
또한 Screen Capture API 문서도 확인해야합니다.