如何在保留类型的同时设置类型化对象的 属性?

How to set a property of a typed object while retaining it's type?

我有一个具体案例,但我也很好奇。

我有一个 canvas,我使用 createImageData 获取它的 ImgData,然后我将它的数据 属性 设置为其他内容,以便使用 PutImageData 并将修改后的 ImgData 传递给它。

我的 PureScript 版本失败了,尽管在控制台中 Javascript 中编写逻辑可以完美运行。 错误是:

foreign.js:423 Uncaught TypeError: Failed to execute 'putImageData' on 'CanvasRenderingContext2D': 
parameter 1 is not of type 'ImageData'.

在 PureScript 中:

getCleanBuffer :: forall e. Context2D -> Eff (canvas :: Canvas | e) ImageData
getCleanBuffer ctx = do
  imgData <- getImageData ctx 0.0 0.0 160.0 144.0
  return imgData { data = buffer }
 where buffer = asUint8ClampedArray $ A.replicate (160*144*4) 0

在控制台中写入此 javascript 有效(arr 是 160*144*4 个零)

var arr2 = new Uint8ClampedArray(arr);
var imgData = ctx.getImageData(0,0,160,144);
imgData.data = arr2;
ctx.putImageData(imgData,0,0);

我调试了 getCleanBuffer,这是我发现的结果

var getCleanBuffer = function (ctx) {
var buffer = Data_TypedArray.asUint8ClampedArray(Data_Array.replicate((160 * 144 | 0) * 4 | 0)(0));
return function __do() {
    var v = Graphics_Canvas.getImageData(ctx)(0.0)(0.0)(160.0)(144.0)();
    var  = {};
    for (var  in v) {
        if (v.hasOwnProperty()) {
            [] = v[];
        };
    };
    .data = buffer;
    return ;

这个 $9(带有修改数据的 ImgData 副本)变量在检查时显示不是 ImgData 类型,就像 v(原始 ImgData)一样,但它只是一个 'Object'。 它缺少 v 拥有的宽度和高度,但即使我在调试期间修复它,我仍然会遇到同样的错误。

我认为问题在于新对象是无类型记录。没有复制宽高是另外一个问题

我可以写一个javascript函数来手动设置数据属性。 但总的来说,这种情况似乎很常见,我肯定错过了什么,不是吗?

谢谢!

在这种情况下,ImageData 的类型不正确,它是记录的类型同义词,但是将 JavaScript class 类型的值准确地视为记录是不安全的您在这里发现的原因。

我已经按照 Phil 的建议打开了 a bug report

对于一般情况,这是镜头派上用场的地方。你会定义一个像 _data :: LensP ImageData Uint8ClampedArray 这样的镜头,然后可以做 imgData # _data %~ buffer 来实现类似于更新语法的东西。

我根本不知道 purescript,所以我不会回答你的问题的标题,但对于你的具体情况,这不是你应该如何创建一个“clean ImageData".

不同的浏览器有不同的实现 ImageData Object and since specs only required a "TypedArray" as the data property, you can't be sure that the type of this buffer should be an Uint8ClampedArray in every UA (related Q/A). (now living specs 请将此 TypedArray 的类型指定为 Uint8ClampedArray)。

但幸运的是,当 canvas API 已经有一个 context2D.createImageData(width, height) method, or a check-supported-browsers ImageData(Uint8ClampedArray) Constructor if your are in worker(其中 createImageData 不可用时,您似乎正在尝试重新发明轮子)

所以只要使用它,它就可以在任何支持 canvas API 的 UA 中工作,而且你不必担心复制任何类型。