StreamProvider asked to provide data for rows and columns out of bounds with to small images
tva-TIS opened this issue · 5 comments
I don't quite know if this really is an issue or belongs to the kind of exceptions StreamProviders seem to be allowed to throw.
I've written a custom StreamProvider that provides data that has been prepared dynamically. Since I don't have control over which image is displayed in my (probably special) usecase I had some images in the TileView that have lower resolution than the TileView covers. The StreamProvider is then asked to provide data for rows and columns that dont exist, as start and end row and column are calculated by the viewport scaling.
Example:
One image that i tested had dimensions of 190x266 pixels and the formula I chose to dynamically determine the TileSize chose a TileSize of 14. At this setup the Provider can Provide 190 / 14 = 13, 5 ~ 14 columns and 266 / 14 = 19 rows. But as the viewport on the device has a multiple of the dimensions the provider is aked to provide 45 columns and 63 rows.
As I said I don't now if this requires a change in the source code, but i thought that this case might appear should at least be brought to the authors attention.
Sorry, I've read your example a couple of times and I'm not at all clear on the issue. What specifically is happening? Maybe you could post your project somewhere with STR...
I'm afraid I probably cannot share the whole project, but i used a project that only had the following java file (and the layout file for the tileView) modified to test my hypothesis of the correlation of the image size with the NullpointerExceptions.
MainActivity.zip
The following code examples however are from the real project.
My StreamProvider looks like this:
private class BitmapStreamProvider implements StreamProvider {
@Override
public InputStream getStream(int column, int row, Context context, Object data) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
((SparseArray<SparseArray<Bitmap>>) data).get(column).get(row).compress(Bitmap.CompressFormat.PNG, 0, bos);
} catch (NullPointerException e){
Log.w(TAG, "Invalid row or column requested, column " + column + " and row " + row, e);
return null;
}
byte[] bitmapdata = bos.toByteArray();
return new ByteArrayInputStream(bitmapdata);
}
}
And the tileView is initialized as following:
new TileView.Builder(tileView)
.defineZoomLevel(bits)
.setTileSize(tileSize)
.setSize(originalBitmap.getWidth(), originalBitmap.getHeight())
.setStreamProvider(new BitmapStreamProvider())
.installPlugin(new MarkerPlugin(context))
.build();
... with bits
being the two-dimensional SparseArray with originalBitmap
sliced down to tileSize
width and height.
So in my example originalBitmap
would now be an image of size 190*266 pixels. The tileSize is calculated by tileSize = (int) Math.sqrt(Math.sqrt((originalBitmap.getWidth() * originalBitmap.getHeight())));
to have larger tileSize
for larger images. For the example image the tileSize
is 14. The algorithm cutting the bitmaps fills bits
with 14
SparseArrays each containing 19
bitmaps which would fit the calculations from my first comment. In populateTileGridFromViewport
however (assuming no scale for now), the tileView
calculates to go over 64 (0-64) rows and 49 (0-49) columns. tileSize
stays 14
as getScale()
and mCurrentDetail.getSample()
both return 1
. rows.start
and columns.start
both are set to 0 as we want to start in the top left corner of the tiles. rows.end
and columns.end
however use viewport values which are not null, on my developement device viewport.bottom
is 896
, and viewport.right
is 688
which are the layout dimensions of the tileView. When calculated through the tileSize
these values will result in a row count that is bigger than the amount of tiles that could be made from the image as long as the image has smaller dimensions than the viewport, because both have been divided by the tileSize, which will lead to NullPointerExceptions in the StreamProvider.
As I said: I'm both aware that the StreamProviders are allowed to throw Exceptions and your library usually displays quite large images, but thought this should be to attention anyway, even if its only for someone wandering about the occuring NullPointerExceptions.
do you see the problem in the math where the grid is computed?
There seem to be further issues with images that do not cover the Viewport of the TileView, even when applying the current change suggestions of #531 (comment).
Discovered so far:
- When setting MaximumScale/ScaleLimits the onClickListeners of the markers aren't called anymore or markers may be invisible entirely
- Image is not correctly vertically centered and first appears at the top of the TileView until touched when in MinimumScaleMode Contain
- Setting a MinimumScaleMode does not have an effect unless MaximumScale/ScaleLimits were set
I will see how far I can dig into the issues myself, but won't open separate issues for know as I don't know how far these issues are connected to each other or if they may be fixed in additional changes within #531