我有一个问题,我有一些问题发送画布的imageData到我的服务器处理它。
下面是发送数据的react/redux操作:
export const edit = (e) => dispatch => {
let payload = store.getState().image.imageData
payload = payload[payload.length-1]
console.log(payload)
const id = e.target.id ? e.target.id : e.target.parentElement.id
fetch(`/api/editing/${id}`, {
method: 'POST',
// headers: {
// "Content-Type": "application/json"
// },
body: JSON.stringify({ imgData: payload })
})
.then(res => res.json())
.then(json => {
dispatch({ type: UPDATE_IMAGE, payload: json.imgData })
// handle response display
})
}
下面是我如何处理请求:
const traitement = require('../../processing/traitement')
router.post('/:type', (req, res) => {
const { imgData } = req.body
const method = req.params.type
const imgDataProcessed = traitement[method](imgData)
return res.status(200).json({ imgData: imgDataProcessed })
})
下面是一个治疗方法的示例:
negatif: function(imgData) {
console.log(imgData)
var n = imgData.data.length;
for(i=0; i<n; i+=4){
imgData.data[i] = 255 - imgData.data[i];
imgData.data[i+1] = 255 - imgData.data[i+1];
imgData.data[i+2] = 255 - imgData.data[i+2];
imgData.data[i+3] = 255;
}
return imgData;
},
console.log(),然后发送(我希望发送内容):
ImageData {data: Uint8ClampedArray(180000), width: 300, height: 150}
data: Uint8ClampedArray(180000) [0, 0, 255, 255, 0, 0, 255, 255, 0, 0,
255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0,
0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0,
0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255,
255, …]
height: 150
width: 300
__proto__: ImageData
我无法粘贴从服务器获得的内容,但我丢失了宽度、高度键,typeof是Object而不是ImageData,数据键是typeof Object而不是Uint 8 ClampedArray。
所以我的问题是:如何使路由访问我发送的相同数据,以便能够处理它?
正如您所看到的,我将它们作为字符串化的json发送,并且在我的服务器上有一个json bodyparser中间件,也许它就是从那里来的。
编辑:感谢Kaiido,我已经修改了我的代码,似乎在1个例外的工作方式
我如何修改我的代码,前面:
let payload = store.getState().image.imageData
payload = payload[payload.length-1]
const id = e.target.id ? e.target.id : e.target.parentElement.id;
console.log(payload)
const meta = {
width: payload.width,
height: payload.height
}
const formData = new FormData();
formData.append("meta", JSON.stringify(meta));
formData.append("data", new Blob([payload.data.buffer]))
fetch(`/api/editing/${id}`, {
method: "POST",
body: formData
})
.then(res => res.arrayBuffer())
.then(buffer => {
console.log(buffer)
const data = new Uint8ClampedArray(buffer)
console.log(data.length)
const newImg = new ImageData(data, payload.width, payload.height)
return newImg
})
背面:
router.post('/:type', (req, res) => {
let form = new formidable.IncomingForm()
form.parse(req, (err, fields, files) => {
fs.readFile(files.data.path, (err, data) => {
const imgProcessed = traitement[req.params.type](data)
console.log(imgProcessed.length)
return res.status(200).json([imgProcessed])
})
})
})
还剩1个问题:假设我使用一个150* 300 px的图像进行测试,我的数据数组应该是180000长(3001504),直到我发送服务器的响应。当前端收到响应时,它调用res.arrayBuffer()
,然后创建一个新的Uint 8 ClampedArray,但在这种情况下,我的长度不超过180000,而是543810。正如Kaiido所说,我可能想对该数组进行切片,我尝试过,但不起作用。
我该怎么切呢?18万个第一次的?18万个最后的?还是其他方式?
2条答案
按热度按时间c9qzyr3d1#
做
这与
JSON.stringify
相反,当您通过stringify发送数据,但在route中不将其解析回原始对象时,需要使用此函数。bmp9r5qi2#
JSON只处理非常少的类型:字符串、数字、数组、对象、布尔值和空值。
没有可枚举属性的ImageData会将 JSON.stringified 转换为空对象
"{}"
。您将丢失所有信息。因此,要避免此问题,您必须在请求中手动发送所有这些信息。
简单地将所需的值移动到另一个对象中听起来相当容易:
但是,您会注意到
data
属性没有以正确的方式进行字符串化。实际上,TypedArray在 JSON.stringified 时被转换为一个简单的对象,它的所有索引都被设置为键。而原本只需要144字节来表示我们的6px*6px图像数据,现在却需要1331字节。
我会让你做更大的图像的数学,但你可能会考虑其他方法...
您最好**发送其底层ArrayBuffer,而不是发送此Uint8ClampedArray的字符串化版本。**这听起来可能需要编写更多代码,但您将保存带宽,甚至可能节省树。
因此,要将ImageData发送到服务器,您需要执行以下操作
现在,在服务器上,为了检索请求的所有部分,您将使用to grab the form-data content,并以File上载的方式访问图像数据。
然后,您必须读取这个上传的文件(例如,使用
fs.readFile(temp_path)
并直接从返回的Buffer执行manips(因为节点中的Buffer是Uint8Array)。完成manips后,可以直接将修改后的缓冲区作为响应发送。
现在在前面,您只需请求将Response作为ArrayBuffer使用,并从此ArrayBuffer生成一个新的ImageData:
这里假设您的前端不需要来自服务器响应的元数据(因为您已经有了它)。
如果您需要一些元数据,那么您可以在ArrayBuffer响应的开头预先挂起它(分配一个插槽,让您知道它的大小,然后 slice() 您接收到的Array,以便获取元数据和实际的图像数据。