Easljs Applying filters to bitmap - javascript

I'm trying to figure out how to add filters ti a video source with easljs. According to the documentation, I can just set filters to the bitmap.filtes property. This doesn't seem to work though. There is no error or anything, the filters are just not applied at all.
One confusion about the documentation, is that it mentions that cache() must be called on the display object in order for filters to be applied but for the bitmap class, it says that cache() should not be called.
Below is the code that I'm using as a test:
var stage = new createjs.Stage('screen');
var video = document.getElementById('source');
var bitmap = new createjs.Bitmap(video);
bitmap.scaleX = 0.44;
bitmap.scaleY = 0.44;
bitmap.y = 30;
bitmap.filters = [
new createjs.ColorFilter(0,0,0,1,255,0,0),
new createjs.BoxBlurFilter(5, 5, 10)
];
stage.addChild(bitmap);

The documentation regarding Bitmap and Filters is misleading - and I will make sure it is updated for the next release.
Caching of a bitmap should be avoided because it will NOT provide any performance benefit, which you will get from caching containers, shapes, and Text. In fact, it can even degrade performance instead because it will use additional memory to store the cached version
But you MUST cache a bitmap to apply filters to it. Add a cache call to your sample, and it should work.
Sorry for any confusion that is caused by the documentation.

Related

How to get usable canvas from Mapbox GL JS

I'm using Mapbox GL, and trying to get a snapshot of it, and merge the snapshot with another image overlaid for output.
I have a HTMLCanvasElement off screen, and I'm first writing the canvas returned from Map.getCanvas() to it, then writing the second (alpha transparent) canvas over that.
The problem is that, though I clearly see elements onscreen in the Map instance, the result only shows the second image/canvas written, and the rest is blank.
So I export just the map's canvas, and I see it is because the map canvas is blank, although a console.log() shows the image data from it to be a large chunk of information.
Here's my export function:
onExport(annotationCanvas: HTMLCanvasElement) {
const mergeCanvas: HTMLCanvasElement = document.createElement('canvas');
const mapCanvas: HTMLCanvasElement = this.host.map.getCanvas();
const mergeCtx: CanvasRenderingContext2D = mergeCanvas.getContext('2d');
mergeCanvas.height = annotationCanvas.height;
mergeCanvas.width = annotationCanvas.width;
mergeCtx.drawImage(mapCanvas, 0, 0);
mergeCtx.drawImage(annotationCanvas, 0, 0);
const mergedDataURL = mergeCanvas.toDataURL();
const mapDataURL = mapCanvas.toDataURL();
const annotationDataURL = annotationCanvas.toDataURL();
console.log(mapDataURL); // Lots of data
download(mapDataURL, 'map-data-only.png'); // Blank image # 1920x1080
download(mergedDataURL, 'annotation.png'); // Only shows annotation (the second layer/canvas) data
}
Is this a bug, or am I missing something?
UPDATE: I sort of figured out what this is about, and have possible options.
Upon stumbling upon a Mapbox feature request, I learned that if you instantiate your Map with the preserveDrawingBuffer option set to false (the default), you wont be able to get a canvas with usable image data. But setting this option to true degrades performance. But you can't change this setting after a Map is instantiated...
I want the Map to perform the best it possibly can!!!!
So, on this answer I stumbled on, regarding a question about three.js, I learned that if I take the screenshot immediately after rendering, I will get the canvas/data that I need.
I tried just calling this.host.map['_rerender']() right before I capture the canvas, but it still returned blankness.
Then searching around in the source code, I found a function called _requestRenderFrame, that looks like it might be what I need, because I can ask the Map to run a function immediately after the next render cycle. But as I come to find out, for some reason, that function is omitted in the compiled code, whilst present in the source, apparently because it is only in the master, and not part of the release.
So I don't really have a satisfactory solution yet, so please let me know of any insights.
As you mentioned in your updated question the solution is to set preserveDrawingBuffer: true upon Map initialisation.
To answer your updated question I think #jfirebaugh's answer at https://github.com/mapbox/mapbox-gl-js/issues/6448#issuecomment-378307311 sums it up very well:
preserveDrawingBuffer can't be modified on the fly. It has to be set at the time the WebGL context is created, and that can have a negative effect on performance.
It's rumored that you can grab the the canvas data URL immediately after rendering, without needing preserveDrawingBuffer, but I haven't verified that, and I suspect it's not guaranteed by the spec.
So although it might be possible to grab the canvas data URL immediately after rendering, it's not guaranteed by the spec.

Avoid cleaning canvas in updateOptions call

I am working in a signals plot program trying to simulate the 'persistence' feature as available in many oscilloscopes.
I would like to prevent dygraph canvas to clean for every updateOptions call. Instead of that, my plot should be preserved until an explicit call for cleaning. This feature will allow me to check if a signal preserves its phase during a certain amount of time.
I tried to use block_redraw parameter set to false in updateOptions function without no success.
Any ideas?
This isn't really something dygraphs is designed to do. You're asking it to render the full history of its data source, rather than the current state of its data source.
That being said, here's the code that clears the plotting canvas:
DygraphCanvasRenderer.prototype.clear = function() {
this.elementContext.clearRect(0, 0, this.width, this.height);
};
So if you override that, it might do what you want:
DygraphCanvasRenderer.prototype.clear = function() {};
That being said, this is liable to break lots of things (like zooming and panning) in addition to giving you the behavior you want. You can see this if you visit the live random data demo page and copy that snippet into the JS console.
Good luck!

Three.js - How to update vertices in a THREE.Points (or THREE.ParticleSystem)?

I'm seeing examples that mention about setting the vertices' (i.e. THREE.Vector3) objects .velocity and seeing the particleSystem's geometry.__dirtyVertices to true.
But I am not seeing either of these properties.
I am using definitely typed definition for three.js revision 75.
If all else fails I will likely resort to manually updating all vertices based on their respective velocity. But I really don't want to do that.
geometry.__dirtyVertices = true; is for pre-r49, in later versions you need to use:
geometry.verticesNeedUpdate = true;
Check this How to update things reference document to find more details on how to update things.

Change color of shape without recreating

I have a project using easelJS in that I'm trying to simply change the color of a shape object. I have a couple of examples but they both seem to indicate I would need to completely redraw the shape with a graphics.beginFill() call again. This seems completely overkill considering that I've stored my shape object already and am able to perform other manipulations on it.
I've also tried to use ColorFilter and ColorMatrix but have not had luck making a clean color change. In some cases the color essentially "overwrites" the detail of the shape.
I have an array of ShapeObject that I store the createjs.Shape() object in.
var ShapeObject = function()
{
this.name;
this.shape;
this.rotation;
this.color;
};
sObject = new ShapeObject();
myShape = new createjs.Shape();
sObject.shape = myShape;
shapes = new Array();
shapes.push(sObject);
Later I am able to retrieve the shape from the array and apply a filter, for example,
s = shapes[i];
filter = new createjs.ColorFilter(0,0,0,1, 255,128,0,0);
s.shape.filters = [ filter ];
Using this same example I'd like to avoid having to completely recreate the shape. I have tried the following but, while it changes color, I lose all the other details of the shape that was originally applied.
s.shape.graphics.clear().beginFill(color);
Does anyone have an idea of how to simply change the color without completely recreating the original shape?
EDIT
Following the answer regarding .command and the createjs command blog post I have created the following.
var theShape = new createjs.Shape();
var fillCommand = theShape.graphics.beginFill("yellow").command;
theShape.graphics.setStrokeStyle(1)
.beginStroke(createjs.Graphics.getRGB(0, 0, 0))
.drawCircle(0, 0, 20)
.moveTo(0,-20)
.lineTo(0,0)
.moveTo(0,0)
.lineTo(20,0);
fillCommand.style = "orange";
Despite being nearly identical to the examples I am receiving the error Uncaught TypeError: Cannot set property 'style' of undefined at the last line above.
I wouldn't use ColorFilter or ColorMatrix, it will likely be much slower. But you could use the Graphics command object, check out the docs: http://www.createjs.com/docs/easeljs/classes/Graphics.html
var fillCommand = myGraphics.beginFill("red").command;
// ... later, update the fill style/color:
fillCommand.style = "blue";

Why is there no reference on image data?

Yes, I know about .getImageData()
I mean, let's say, I have to change some pixels:
var imageData = ctx.getImageData(...);
Seems, this method give me completely new copy of "real" (hiden somewhere deep from me) image-data.
I say that, because if you create new one:
var imgData2 = ctx.getImageData(.../*same parameters as before*/);
and compare two buffers:
imageData.data.buffer === imgData2.data.buffer; //false
So, each time it create new copy from it's bitmap. Oh my Gosh, Why? Okay, go further:
/*...apply some new changes to the imageData in a loop...*/
Nothing special above. But now, it's time to put this back:
ctx.putImageData(imageData, ...);
And this one inside itself run new loop and copy my imageData.
So much extra work! Is there a way to get actual imageData and manipulate it without get/put? And if no - I'm ask again - WHY? Is it security reasons? What they afraid I can do with that pixels?
Thank you!
Short answer :
No.
Not so long Answer :
You may be able to achieve it with some hacks but that would be such a pain.
Explanations :
According to the specs, getImageData returns a TypedArray which contains the canvas' image data, not a pointer to the live imageData as a modifiable object.
To paint on a canvas, you have to use methods such as fill, stroke, drawImage or putImageData ; that would make even less sense that each time you iterate through the array, the actual canvas image get modified.
Each time you call getImageData, a new TypedArray (note that the choice of the actual type is up to the UA) is created and filled with the current data of the canvasImage. This way, you can call this method, make different alterations on the ArrayBuffer, without modifying the actual image into the canvas (so you can store it, or call the method again).
As to why the buffer of the returned ImageData is not the same on each call, I think it is because "Pixels must be returned as non-premultiplied alpha values", but for performances, they do store it as premultiplied. You can see here the de-premultiplication operation from Firefox source code, which actually fills a new Uint8ClampedArray.
Also, it avoids to check if the canvasImage as been modified since the last call, and ensure you always get its current ImageData.

Categories

Resources