nglviewer / ngl

WebGL protein viewer
http://nglviewer.org/ngl/
MIT License
668 stars 170 forks source link

Can height and width be specified for makeImage? #265

Open fredludlow opened 7 years ago

fredludlow commented 7 years ago

I was wondering how easy it would be to add height and width parameters for screenshots? There's a bit of hackery I can do to read the blob result from makeImage into a new Image, add it to an invisible canvas element, scale it and re-save it but that's quite a convoluted route. I'm not quite sure how makeImage works underneath so wasn't sure if it would be possible to add them or if the size is necessarily determined by the canvas element size.

arose commented 7 years ago

No, currently there is only the factor parameter for scaling. It has bugged me for a while and being able to set the width and height directly is definitely a feature I want.

Due to the way WebGL works it is best to reuse the canvas. There are two options. Either cropping an image like you described or resizing the canvas. If we can hide rescaling the canvas I would go that route.

fredludlow commented 7 years ago

(Have been away and just coming back to this..)

Rescaling the canvas would also have the benefit of being able to render beyond normal screen resolution. Any ideas how you might do it? (Maybe replace the canvas with a static (possibly greyed out?) image while you manipulate the canvas then restore afterwards?)

I have a gist for doing it the other way (rescaling the 2D image from makeImage) in case you or anyone else is interested. This doesn't take care of preserving aspect ratio or anything (should be an easy addition), but gets the various async calls in order https://gist.github.com/fredludlow/a384a15965c70510cddfd21cccda96ba

arose commented 7 years ago

Maybe replace the canvas with a static (possibly greyed out?) image while you manipulate the canvas then restore afterwards?

Yes, that sounds good

Rescaling the canvas would also have the benefit of being able to render beyond normal screen resolution.

To go beyond the max screen resolution you have to render the image in multiple rounds and then stitch it together which is exactly how it is done currently :)

I meant rescaling mostly as a way to have the most effective rendering as in "only render what you use in the end" which would not be the case with cropping. However cropping is probably not too bad in terms of efficiency as the aspect ratio is usually similar to what the user wants from a screenshot.

fredludlow commented 7 years ago

Ah, I'd just assumed I could set the canvas to position absolute, visibility hidden and resize arbitrarily? (and restore afterwards)

arose commented 7 years ago

Ah, I'd just assumed I could set the canvas to position absolute, visibility hidden and resize arbitrarily? (and restore afterwards)

No, the canvas size is not changed at all as it is currently implemented. Most of the code is in the TiledRenderer. A key part is viewer.camera.setViewOffset which alows just rendering part of a view frustum.

It you look at Max Viewport Dimensions (http://webglreport.com/) you see that by resizing the canvas you only go to 2x or 4x of the screen size.

fredludlow commented 7 years ago

Just re-read above and the relevant code and realised I'm doing things in a rather silly way (I'd forgotten factor is available). I've implemented something (as an external utility) that saves Image, puts it in front of the canvas, resizes canvas and calls makeImage (then undoes everything) - there's a rough sketch in this gist.

https://gist.github.com/fredludlow/bcc70794d43350c219b2a9b94750b8b7

This causes some flickering as stuff gets resized and moved around (it's all a bit indeterminate and depends presumably at which point the browser manages to squeeze in a re-flow/re-render).

If it doesn't all feel like too much of a big hack I can clean it up and make a PR, but I'm aware I might be doing 20 steps when 3 will do it.