-
-
Notifications
You must be signed in to change notification settings - Fork 607
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement per-image flipping #1903
Conversation
This is now working well enough for some review. Note that there is a stealth bug fix in there - viewport clipping now works with wrapped images. This is because of the new getTileBounds wrapper which is aware of wrapping and tiling. Open questions:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fantastic! Thank you for taking this on, @ali1234! My apologies for not reviewing it sooner... 2020 did a number on my schedule.
The code looks good to me. Some thoughts:
- I think getTileBounds should be a private member (until such time as we discover we want to add it to the API officially). We can do that by adding a
_
prefix to its name and adding@private
to its doc comment. - I think
getFlip
is good and yes, we should have asetFlip
, so we can change it while the app is running. - The documentation you've already added looks good. What additional documentation were you thinking of?
I was thinking more about the website high level docs and examples, rather than the autodocs (which I don't really know if I've done right, not a JS dev here.) Will have a look at the other stuff at the weekend. |
Well, having a page for flip would certainly be great! We have one for rotation (http://openseadragon.github.io/examples/ui-rotation/) but not for flip. If you're up for tackling that, it's in another repository: https://github.com/openseadragon/site-build/tree/master/www. The JS docs you did look proper to me!
Great! I'll get back to you sooner than I did last time! BTW, just a note here: I tried this patch and tested flipping the image by itself, flipping the entire viewport along with the image, and rotating the viewport along with the image, and everything worked properly :) |
Well I know for a fact there is at least one edge case when you flip both the image and the viewport, see https://al.zerostem.io/~al/dzi/ By default you have an "xray" view through the top layer so you can see the bottom layer (which is flipped so it lines up with the top). If you click "bottom", now the bottom layer is normally shown and the top layer is the "xray". Now click "flip" to flip the viewport (so writing on the bottom layer is not reversed), and pan around. It all works except now the xray view moves opposite to the panning direction. This could be my code, but I couldn't figure out a nice way to fix it. I think it happens in some of the examples too, if you modify them slightly to use per-image flipping. |
Hmm... looks like just hitting the flip button is enough to get that to happen (you don't need to click "bottom" first). One thing we do sometimes with major features like this is make a new page in the test/demo folder that shows off the various possibilities and provides a good test bed for situations like this. It might be worth creating such a page for "flip" and including a simplified version of this scenario, for easier debugging (and to be able to keep an eye on regressions). That would make it easier for other people to take a look at figuring out the issue as well. Anyway, thank you for spotting this issue... definitely worth fixing! |
This wraps the implementation in tileSource but provides support for wrapping. It does not support getting the source bounds. Using this function instead of the tileSource version allows the viewport clipping optimization to work with wrapping.
This will flip each individual tile on a per image bases. However the tiles are now drawn in the wrong locations. Clipping etc works. this is implemented for Canvas and HTML renderers.
This completes the per-image flip implementation. Tile bounds are re-positioned within the image. When rendering, the x ordinals are remapped to the flipped ones. To use, set "flipped" on the image instead of the viewer. The code is compatible with rotations and wrapping. Implements openseadragon#1553
This ensures that seams are not visible in Firefox and Safari when the image is wrapped horizontally and also flipped.
This isn't complete - the flip toggles do not work as setFlip() is not implemented. The second image is currently always flipped.
Rebased and added an example. The problem with images panning the wrong way actually seems to be #1900 which I forgot I reported. You can see it in the example by toggling rotate on either image while viewport flip is on. It seems to happen without the changes I've made in this pull request. |
Regarding getTileBounds: There is already a public |
Above |
This doesn't fully work - even raising a bounds-change doesn't seem to be enough.
So I found |
Flipping an image changes the bounds of each tile. The existing code assumes that cannot happen. getTile() calculates the tile bounds the first time it is asked for a particular tile. It then caches and returns the same time on every subsequent call. getTile() has a check to test if a tile exists in the cache. If it does not, the tile is created and inserted. In order to make tiles be rebuilt after a flip, we only need to check if the tile's flip matches the image's flip. If not, we can recreate the tile as if it did not exist. To make this a bit clearer, the tile's flipped flag is now set in getTile() rather than positionTile(). This makes setFlip() work.
Question: do I need to do anything special when deleting a cached tile from |
Perhaps a better way to explain what that last change does: Previously
and I have changed it to:
This makes individual tile bounds get recalculated when flip changes, so it makes |
Thank you for adding the example! It really helps. Rebasing, though, makes it harder to continue the code review from where I last left off; instead I have to reread all of the code again. I know some projects prefer rebasing, but I like the continuity of being able to see the full change history. Not a big deal, just letting you know :) One minor thing on the example... if you load the images when you create the viewer (rather than using
I see! I've confirmed that this patch does not introduce the issue, so we don't need to hold up this patch on a fix for that issue (though it would of course be lovely to fix at some point).
I'm not suggesting that it be literally private in a code sense, so the unbound method can continue to call it. I'm just saying we don't necessarily want to indicate to people using the library that it's something for them to use. Prefixing the method name with
Very clever! That seems like a fine solution. I can't think of anything else that would need to be done. When I tested it in the demo, it responded quite nicely. I suppose it would be interesting to know how it looks with a lot of tiles over a slower connection. That said, it sure looks like it just uses the tiles that are already in memory. So, it looks like this patch is probably ready to land! Is there anything else you think it needs? I suppose it would be nice to have some unit tests for this new functionality, but only if you're up for it... I wouldn't consider it a requirement. Thank you for making this happen! |
As far as I can tell For |
Don't need double negation and brackets here.
Adds tiled images to the viewer at creation so that they are properly centred. This also checks the current state of the test checkboxes on loading. Some browsers, notably Firefox, will remember the value of checkboxes across reloads. This can lead to the checkboxes being out of sync with with viewer after a reload. An alternative is to set autocomplete="off" on each checkbox element. This will force the browser to reset the field to the default specified in the HTML. However I think checking the actual value is preferable as it means the defaults are only specified in one place.
I think this is good... if you flip an image, you'll end up with twice the tile records (the flipped version and the non-flipped version), but they will all share images at the tileCache level. I could be wrong, but I think that's a reasonable way to work it.
Yeah, makes sense. Let's stick with it being public, then. Your recent changes look good. What say you, shall we land this? |
I'm happy for this to be merged. |
Just found a bug. |
Makes setFlip() raise a bounds change, and makes the navigator copy the image flip in addition to the other properties, when receiving the bounds signal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch!
OK, I'll merge this soon. Thank you for all the hard work on this!
* master: (27 commits) Changelog for #1968 Fixing issue where the ajaxHeaders were not being set for image requests Changelog for #1865 Changelog for #1937 Changelog for #1903 refactor: moved methods that belongs together closer Make setFlip() update the navigator refactor: use pixelDensityRatio in getPixelRatio() fix: removes resize event on destroy docs: fixed typo and corrected the comment fix: made updatePixelDensityRatio private Improve the flipping example Tidy up the tile/image flip check Force reload tiles when the tile's flip doesn't match the image Add a basic setFlip method to TiledImage Add flipping example Correctly set the rightmost tile property when flipped Render the flipped columns in reverse order Store the flipped state in each tile and render it as such Introduce getTileBounds method for tiledImage ...
This works by re-arranging the tiles within the image, and then rendering each tile flipped horizontally.
To use, set "flipped" on the image instead of the viewer.
Changing the flip state after loading is not yet supported. It will require rebuilding the tile bounds.
Implements #1553