POST canvas 到网络 api
POST canvas to web api
我正在使用 cloudsight api http://cloudsight.readme.io/v1.0/docs
以及我 post 数据所在的字符串。
我还有 canvas 来自网络摄像头的图像。我正在尝试将它发送到 api,但是当我序列化它时 [image] 是空白的。
来自服务器的响应:
{"error":{"image":["can't be blank"]}}
简短片段:
var dataURL = canvas.toDataURL('image/jpeg', 0.5);
var blob = dataURItoBlob(dataURL);
var fd = new FormData(document.forms[0]);
fd.append("file", blob);
/*some code*/
ajax.send("image_request[image]=" + image + "&image_request[locale]=en_US");
// Put event listeners into place
window.addEventListener("DOMContentLoaded", function() {
// Grab elements, create settings, etc.
var canvas = document.getElementById("canvas"),
context = canvas.getContext("2d"),
video = document.getElementById("video"),
videoObj = {
"video": true
},
errBack = function(error) {
console.log("Video capture error: ", error.code);
};
// Put video listeners into place
if (navigator.getUserMedia) { // Standard
navigator.getUserMedia(videoObj, function(stream) {
video.src = stream;
video.play();
}, errBack);
} else if (navigator.webkitGetUserMedia) { // WebKit-prefixed
navigator.webkitGetUserMedia(videoObj, function(stream) {
video.src = window.URL.createObjectURL(stream);
video.play();
}, errBack);
} else if (navigator.mozGetUserMedia) { // WebKit-prefixed
navigator.mozGetUserMedia(videoObj, function(stream) {
video.src = window.URL.createObjectURL(stream);
video.play();
}, errBack);
}
// Trigger photo take
document.getElementById("snap").addEventListener("click", function() {
context.drawImage(video, 0, 0, 300, 190);
saveImage();
});
}, false);
function saveImage() {
var dataURL = canvas.toDataURL('image/jpeg', 0.5);
var blob = dataURItoBlob(dataURL);
var fd = new FormData(document.forms[0]);
fd.append("file", blob);
var ajax = new XMLHttpRequest();
ajax.open('POST', 'http://api.cloudsightapi.com/image_requests', true);
ajax.setRequestHeader("Authorization", "CloudSight 0QssZRTUHaRvU1Tt45fnDw");
ajax.setRequestHeader("Accept", "application/json");
ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
ajax.onreadystatechange = function() {
console.log(ajax.responseText);
}
ajax.send("image_request[image]=" + fd + "&image_request[locale]=en_US");
alert("image_request[image]=" + fd + "&image_request[locale]=en_US");
/* ajax.send("image_request[remote_image_url]=http://images.kaneva.com/filestore10/5860810/7181471/iUloveUgs.jpg ");*/
}
function dataURItoBlob(dataURI) {
// convert base64/URLEncoded data component to raw binary data held in a string
var byteString;
if (dataURI.split(',')[0].indexOf('base64') >= 0)
byteString = atob(dataURI.split(',')[1]);
else
byteString = unescape(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to a typed array
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], {
type: mimeString
});
}
body {
margin: 0;
}
video {
width: 100%;
height: 100%;
}
#snap {
margin-top: 30px;
position: absolute;
right: 50%;
width: 64px;
height: 64px;
transform: translateX(50%);
text-decoration: none;
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAED0lEQVR4Xu2b4XnUMAyGpQmACWgngE5AOwFlAugElAkoE9BOQDsB7QSwAWUC2gm4TiCe75Dz5K62E9uyE8jpz/25nK3XsvRZzjEt3Hjh/tMOwC4CFk5gtwUsA0BEnhLRWyLCZw1bEdEVM+PTxMwiQJ3/QUR7JjML/8gtER1ZQbAEcEZEHys7737+AzOfW4xlCeBXg9V3Pt8y88FsAIjISyJC+Le0fWa+Kx3QJAJEBOH4vnQyic+bbAMrAC3D33QbFAOYKPwdhOJtYAHgUmt/YgSbfP2CmU9LfikbgNZ97HuUvykN4wNEljjaACAih5rM8FlLzU0FC4C+Kyx8rq0DICJfiOjdVLNrPO4lM590ABbmvGO9hsAa9t8arcADEV0TEQQMNL3bt9huEFM4RxwT0ZNG8zkCAEzodeUBr4jonJnh9KBpaUV2x8mypt0AwO+KCe+GiE5zJauIICKgMmst0AoApBLiE2aGRig2EUFyRpJOMUQdthoq2qvQgzUAYJ8fjg33sR7ptkD5GpMfPjFzp09EBM95IVgDqOK8g5QA4aC/ACIS7FVYAxgV9qoiX/RyD6rBzzFqbuR2eMPMSO5rE5GgXLcEgF5dVEj1lCZKnc8wacjaTqn5vhRzSL8PoKgi9xr6QbluBQChvxdaQV3xzwlKEyuG875X32t1QEkdkw+iacYKwEbS6Y+ozkNoQeikWLT5GdvXKYNYAQiey0Xkq6q7lHm573aaffthjQI0YorMAgCSl3d1RyasIQc2EtpWdCFKkEyzzQJAsDcnIhatsjtm3g8kQyQ65JZsswCAS4pHWdu4VebdYhYHuZoAilent6zeKJsFAGb2ttWssrRCiFWZorNMcQQsHgARhfan5V2hNwIsSmFxBOhNrS8JQu5CA1iYtxTOIgcQUfAAJCKQsqVy9YGZvR1qC51hEQHBQ5BRIowlwOJ2ngWAFTM/CwgVrBy6MrlRMHTIKm7nWQCA7zG5mnt1Hm2uiIhJjrECEJSroJPQyXGBNNhZMpLZZAUAE492g7RkoTQOtbrRzDyLdZItkp8jbQkAGR+aIHpJqSAQvv37R3dvdz3UQtfn8TaKyd2lJQBANX2Dy9MDgNM5zZWgFrEGgIGCTYwSRZTRVhs1XA0A5pFQ0FYbhFALAAbGvkZ5jHZ4h2aocheS2mTPb49XE4AbCwCg5pJAqON48RLJspq1AOAmjwQJCJDO3lti1Qsok3A6tYucBaklAN8EHYgmzvomAADQ6s+z8P37D90DwBRvec4F3QUAlJ7Y5uJM6jz+njT1sGJyskqdwcTfX59g+6/JIfPiUvJ/zwe4MT52lehRS1vP2ZNl5cpRgf8ZdO8NYKzsV2UrT7TZz+8ANEM904F2ETDThWk2rcVHwB87rBc0IyZ5+AAAAABJRU5ErkJggg==");
}
#snap:active {
opacity: 0.85;
}
.panel {
position: fixed;
bottom: 0px;
width: 100%;
margin-top: -4px;
background-color: #fc0;
height: 120px;
}
.result {
display: inline-block;
width: 100%;
height: 100%;
}
#overlay {
height: 80%;
width: 80%;
margin: 0 auto;
background: white;
color: black;
padding: 10px;
position: absolute;
top: 5%;
left: 10%;
z-index: 1000;
display: none;
/* CSS 3 */
border-radius: 10px;
}
#mask {
/* create are mask */
position: fixed;
top: 0;
left: 0;
background: rgba(0, 0, 0, 0.6);
z-index: 500;
width: 100%;
height: 100%;
display: none;
}
/* use :target to look for a link to the overlay then we find are mask */
#overlay:target,
#overlay:target + #mask {
display: block;
opacity: 1;
}
.close {
/* to make a nice looking pure CSS3 close button */
display: block;
position: absolute;
top: -20px;
right: -20px;
background: red;
color: white;
height: 40px;
width: 40px;
line-height: 40px;
font-size: 35px;
text-decoration: none;
text-align: center;
font-weight: bold;
-webkit-border-radius: 40px;
-moz-border-radius: 40px;
-o-border-radius: 40px;
border-radius: 40px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<video id="video" class="video" autoplay></video>
<div id="qw" class="panel">
<a href="#overlay" id="snap"></a>
</div>
<div id="overlay">
<a href="#" class="close">×</a>
<canvas class="result" id="canvas"></canvas>
</div>
<div id="mask" onclick="document.location='#';"></div>
</body>
</html>
我有一个问题。您不能从客户端发出跨域 post 请求,除非您为请求和响应服务器都设置了 allow-orgin。
您正在尝试将图片作为表单 (fd) 中的字段发送。这不适用于二进制数据 - 至少您将无法使用服务器端的普通工具集处理它。
您必须将二进制数据作为 multipart/formdata 发送,其中文件显示为它自己的 "part"。 Mozilla 有一些 excellent documentation how to do that from JavaScript.
我正在使用 cloudsight api http://cloudsight.readme.io/v1.0/docs 以及我 post 数据所在的字符串。
我还有 canvas 来自网络摄像头的图像。我正在尝试将它发送到 api,但是当我序列化它时 [image] 是空白的。
来自服务器的响应:
{"error":{"image":["can't be blank"]}}
简短片段:
var dataURL = canvas.toDataURL('image/jpeg', 0.5);
var blob = dataURItoBlob(dataURL);
var fd = new FormData(document.forms[0]);
fd.append("file", blob);
/*some code*/
ajax.send("image_request[image]=" + image + "&image_request[locale]=en_US");
// Put event listeners into place
window.addEventListener("DOMContentLoaded", function() {
// Grab elements, create settings, etc.
var canvas = document.getElementById("canvas"),
context = canvas.getContext("2d"),
video = document.getElementById("video"),
videoObj = {
"video": true
},
errBack = function(error) {
console.log("Video capture error: ", error.code);
};
// Put video listeners into place
if (navigator.getUserMedia) { // Standard
navigator.getUserMedia(videoObj, function(stream) {
video.src = stream;
video.play();
}, errBack);
} else if (navigator.webkitGetUserMedia) { // WebKit-prefixed
navigator.webkitGetUserMedia(videoObj, function(stream) {
video.src = window.URL.createObjectURL(stream);
video.play();
}, errBack);
} else if (navigator.mozGetUserMedia) { // WebKit-prefixed
navigator.mozGetUserMedia(videoObj, function(stream) {
video.src = window.URL.createObjectURL(stream);
video.play();
}, errBack);
}
// Trigger photo take
document.getElementById("snap").addEventListener("click", function() {
context.drawImage(video, 0, 0, 300, 190);
saveImage();
});
}, false);
function saveImage() {
var dataURL = canvas.toDataURL('image/jpeg', 0.5);
var blob = dataURItoBlob(dataURL);
var fd = new FormData(document.forms[0]);
fd.append("file", blob);
var ajax = new XMLHttpRequest();
ajax.open('POST', 'http://api.cloudsightapi.com/image_requests', true);
ajax.setRequestHeader("Authorization", "CloudSight 0QssZRTUHaRvU1Tt45fnDw");
ajax.setRequestHeader("Accept", "application/json");
ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
ajax.onreadystatechange = function() {
console.log(ajax.responseText);
}
ajax.send("image_request[image]=" + fd + "&image_request[locale]=en_US");
alert("image_request[image]=" + fd + "&image_request[locale]=en_US");
/* ajax.send("image_request[remote_image_url]=http://images.kaneva.com/filestore10/5860810/7181471/iUloveUgs.jpg ");*/
}
function dataURItoBlob(dataURI) {
// convert base64/URLEncoded data component to raw binary data held in a string
var byteString;
if (dataURI.split(',')[0].indexOf('base64') >= 0)
byteString = atob(dataURI.split(',')[1]);
else
byteString = unescape(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to a typed array
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], {
type: mimeString
});
}
body {
margin: 0;
}
video {
width: 100%;
height: 100%;
}
#snap {
margin-top: 30px;
position: absolute;
right: 50%;
width: 64px;
height: 64px;
transform: translateX(50%);
text-decoration: none;
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAED0lEQVR4Xu2b4XnUMAyGpQmACWgngE5AOwFlAugElAkoE9BOQDsB7QSwAWUC2gm4TiCe75Dz5K62E9uyE8jpz/25nK3XsvRZzjEt3Hjh/tMOwC4CFk5gtwUsA0BEnhLRWyLCZw1bEdEVM+PTxMwiQJ3/QUR7JjML/8gtER1ZQbAEcEZEHys7737+AzOfW4xlCeBXg9V3Pt8y88FsAIjISyJC+Le0fWa+Kx3QJAJEBOH4vnQyic+bbAMrAC3D33QbFAOYKPwdhOJtYAHgUmt/YgSbfP2CmU9LfikbgNZ97HuUvykN4wNEljjaACAih5rM8FlLzU0FC4C+Kyx8rq0DICJfiOjdVLNrPO4lM590ABbmvGO9hsAa9t8arcADEV0TEQQMNL3bt9huEFM4RxwT0ZNG8zkCAEzodeUBr4jonJnh9KBpaUV2x8mypt0AwO+KCe+GiE5zJauIICKgMmst0AoApBLiE2aGRig2EUFyRpJOMUQdthoq2qvQgzUAYJ8fjg33sR7ptkD5GpMfPjFzp09EBM95IVgDqOK8g5QA4aC/ACIS7FVYAxgV9qoiX/RyD6rBzzFqbuR2eMPMSO5rE5GgXLcEgF5dVEj1lCZKnc8wacjaTqn5vhRzSL8PoKgi9xr6QbluBQChvxdaQV3xzwlKEyuG875X32t1QEkdkw+iacYKwEbS6Y+ozkNoQeikWLT5GdvXKYNYAQiey0Xkq6q7lHm573aaffthjQI0YorMAgCSl3d1RyasIQc2EtpWdCFKkEyzzQJAsDcnIhatsjtm3g8kQyQ65JZsswCAS4pHWdu4VebdYhYHuZoAilent6zeKJsFAGb2ttWssrRCiFWZorNMcQQsHgARhfan5V2hNwIsSmFxBOhNrS8JQu5CA1iYtxTOIgcQUfAAJCKQsqVy9YGZvR1qC51hEQHBQ5BRIowlwOJ2ngWAFTM/CwgVrBy6MrlRMHTIKm7nWQCA7zG5mnt1Hm2uiIhJjrECEJSroJPQyXGBNNhZMpLZZAUAE492g7RkoTQOtbrRzDyLdZItkp8jbQkAGR+aIHpJqSAQvv37R3dvdz3UQtfn8TaKyd2lJQBANX2Dy9MDgNM5zZWgFrEGgIGCTYwSRZTRVhs1XA0A5pFQ0FYbhFALAAbGvkZ5jHZ4h2aocheS2mTPb49XE4AbCwCg5pJAqON48RLJspq1AOAmjwQJCJDO3lti1Qsok3A6tYucBaklAN8EHYgmzvomAADQ6s+z8P37D90DwBRvec4F3QUAlJ7Y5uJM6jz+njT1sGJyskqdwcTfX59g+6/JIfPiUvJ/zwe4MT52lehRS1vP2ZNl5cpRgf8ZdO8NYKzsV2UrT7TZz+8ANEM904F2ETDThWk2rcVHwB87rBc0IyZ5+AAAAABJRU5ErkJggg==");
}
#snap:active {
opacity: 0.85;
}
.panel {
position: fixed;
bottom: 0px;
width: 100%;
margin-top: -4px;
background-color: #fc0;
height: 120px;
}
.result {
display: inline-block;
width: 100%;
height: 100%;
}
#overlay {
height: 80%;
width: 80%;
margin: 0 auto;
background: white;
color: black;
padding: 10px;
position: absolute;
top: 5%;
left: 10%;
z-index: 1000;
display: none;
/* CSS 3 */
border-radius: 10px;
}
#mask {
/* create are mask */
position: fixed;
top: 0;
left: 0;
background: rgba(0, 0, 0, 0.6);
z-index: 500;
width: 100%;
height: 100%;
display: none;
}
/* use :target to look for a link to the overlay then we find are mask */
#overlay:target,
#overlay:target + #mask {
display: block;
opacity: 1;
}
.close {
/* to make a nice looking pure CSS3 close button */
display: block;
position: absolute;
top: -20px;
right: -20px;
background: red;
color: white;
height: 40px;
width: 40px;
line-height: 40px;
font-size: 35px;
text-decoration: none;
text-align: center;
font-weight: bold;
-webkit-border-radius: 40px;
-moz-border-radius: 40px;
-o-border-radius: 40px;
border-radius: 40px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<video id="video" class="video" autoplay></video>
<div id="qw" class="panel">
<a href="#overlay" id="snap"></a>
</div>
<div id="overlay">
<a href="#" class="close">×</a>
<canvas class="result" id="canvas"></canvas>
</div>
<div id="mask" onclick="document.location='#';"></div>
</body>
</html>
我有一个问题。您不能从客户端发出跨域 post 请求,除非您为请求和响应服务器都设置了 allow-orgin。
您正在尝试将图片作为表单 (fd) 中的字段发送。这不适用于二进制数据 - 至少您将无法使用服务器端的普通工具集处理它。
您必须将二进制数据作为 multipart/formdata 发送,其中文件显示为它自己的 "part"。 Mozilla 有一些 excellent documentation how to do that from JavaScript.