1

I have a specific case, but I'm also curious in general.

I have a canvas, I get it's ImgData using createImageData, and I set it's data property to be something else, in order to then use PutImageData and pass it this modified ImgData.

My PureScript version fails, although writing the logic in Javascript in the console works flawlessly. The error is:

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

In 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

Writing this javascript in console works (arr is 160*144*4 zeroes)

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

I've debugged getCleanBuffer and here's what I found

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 $9 = {};
    for (var $10 in v) {
        if (v.hasOwnProperty($10)) {
            $9[$10] = v[$10];
        };
    };
    $9.data = buffer;
    return $9;

This $9 (ImgData copy with modified data) variable, when inspected, is revealed not to be of type ImgData, like v (the original ImgData) was, but it's just an 'Object'. It's missing the width and height which v had, but even when I fix it during debug I still get the same error.

I think the problem is that the new object is a typeless record. The fact that the width and height were not copied is another problem.

I can write a javascript function to set the data attribute manually. But this case in general, seems like a common one, surely I'm missing something, am I not?

Thanks!

4

2 回答 2

3

In this case the type of ImageData is incorrect, it's a type synonym for a record, but it is not safe to treat JavaScript class typed values as records for exactly the reason you're discovering here.

I've opened a bug report as Phil suggested.

For the general case, this is where lenses come in handy. You'd define a lens like _data :: LensP ImageData Uint8ClampedArray, and then could do imgData # _data %~ buffer to achieve something similar to the update syntax.

于 2016-05-11T23:11:35.620 回答
0

I don't know purescript at all, so I won't answer the title of your question, but for your precise case, this is not how you should create a "clean ImageData".

Different browsers have different implementations of the 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 do specify the type of this TypedArray as Uint8ClampedArray).

But fortunately enough, it seems that you are trying to reinvent the wheel, when the canvas API already has a context2D.createImageData(width, height) method, or a check-supported-browsers ImageData(Uint8ClampedArray) Constructor if your are in worker (where createImageDatais not available)

So just use it, it will work in any UA supporting the canvas API, and you won't have to worry about copying any type.

于 2016-05-12T01:21:44.477 回答