bumptech / glide

An image loading and caching library for Android focused on smooth scrolling
https://bumptech.github.io/glide/
Other
34.67k stars 6.12k forks source link

Subsampling for dynamic zooming #1305

Open MFlisar opened 8 years ago

MFlisar commented 8 years ago

Is there a way to use subsampling with glide? I want to have a feature like Ion's (https://github.com/koush/ion) deepZoom feature...

I use a view like PhotoView of Chris Banes (https://github.com/chrisbanes/PhotoView) and want to show a real big image. I now want to dynamically update the shown image while zooming into the image... Ion managed to do this with PhotoView...

Is there any way to do this with glide?

TWiStErRob commented 8 years ago

No out of box support as far as I know. I think the closest you can get is wiring your own model/loader/fetcher/decoder that uses RegionBitmapDecoder, see what I did in https://github.com/bumptech/glide/issues/700#issuecomment-150317491.

TWiStErRob commented 8 years ago

Note: subsampling is automatically used when decoding the image by default, based on target size. The largest inSampleSize is used where quality is not lost and then the decoded image is fit/cropped. This saves a lot of memory, see Downsampler.

MFlisar commented 8 years ago

I will check that comment...

But wouldn't this be a nice feature for glides official api? It seems to be one main use case...

TWiStErRob commented 8 years ago

It's a main use case for other libraries, Glide is focused single image loading. I agree, it would be a nice feature, however notice that Glide doesn't have any special view or drawee, the target is just a plain ImageView most of the time. This feature would require some special view like PhotoView shows. If you figure out a way, and you give a design outline, or a PR I think it would be very welcome and considered.

@sjudd can you elaborate why this is not supported? My above reasons are just educated guesses.

MFlisar commented 8 years ago

I think, supporting this with a view like PhotoView would be a start already... I will check the link and try to get this working with PhotoView...

TWiStErRob commented 8 years ago

I just found https://github.com/chrisbanes/PhotoView/blob/master/sample/src/main/java/uk/co/senab/photoview/sample/PicassoSampleActivity.java which is very similar to Glide. You can add a listener or create a custom target (extending *ImageViewTarget) to update the attacher. I guess your problem is that you don't want to load the whole image into memory (ala .override(Target.SIZE_ORIGINAL)), but want to somehow load a downsampled/cropped image or tile.

MFlisar commented 8 years ago

Exactly. Using above, will probably just tell glide to load an image in for example 1/4 of whole resolution, then 1/2 of whole resolution and then full resolution... Which does not solve the memory problem...

MFlisar commented 8 years ago

@TWiStErRob The link you posted (https://github.com/bumptech/glide/issues/700#issuecomment-150317491) just shows how to load regions of an image, correct? I don't oversee something, do I?

For reacting to zooming and update the regions that should be displayed in the ImageView there's no example yet anywhere, correct?

TWiStErRob commented 8 years ago

Yes, it's just a way of using a custom decoder to decode parts of the (very tall) image. Reacting to user input not included.

It looks like Ion loads the tiles similar to how we load GIF frames. It has one huge drawable for handling GIF, DeepZoom, and probably crossfade as well.

MFlisar commented 8 years ago

I have some general question to this topic, is following scenario doable with glide:

1) Decide how many tiles I want to create from an image Let's define, we want tiles of a maximum size of 1000 x 1000

2) Create tiles for all zooming levels depending on tile size from 1 As an example, let's take a 4000 x 4000 image => tiles are 1000 x 1000 or less. We create following tiles:

3) Caching All tiles should be cached seperately!

4) WHAT NEXT Idea1

Idea2

Any thoughts on this? I think idea2 looks good. Do I oversee something? Any feedback is very appreciated.

I would probably handle the tiles with different Uris like uri:tileSize:x:y where the "uri" is the base uri and the "tileSize" defines the resolution (full, half, quarter, ...) and "x" and "y" define the tile position in a 2 dimesnional grid... And the Drawable would know ALL uris and use them to load or get the regions bitmaps... this also results in that I don't have to care about caching, as different uris are already working out of the box and so point 3 of my list is done without worrying about it by my implementation

TWiStErRob commented 8 years ago

You need a very simple decoder wrapping region decoder, the interesting part is getting the region to that decoder. If each tile is a separate Glide load then your separate caching is solved out of the box. Using a complex uri is pointless, because Glide can load arbitrary objects, just create a custom loader/fetcher that forwards your stuff to the decoder (e.g. google PassthroughModelLoader). Then the decoder can decode the region based on that input object, or use the method I used in #700 to get the region to the decoder. The #700 method has the advantage of being able to load from anywhere.

The drawable needs to know which part is visible, yes, and then it can calculate which tiles are needed and fire separate Glide loads for each tile, see GifFrameLoader.loadNextFrame(), which fires a single load for the next frame. You don't need a special ImageView to handle this. Just attach the listener onto any view (preferable the ImageView though) and manipulate your zooming Drawable. It can invalidate itself on that manipulation which will be delegated to the ImageView via Drawable.Callback which will result in a re-draw. You'll also need to invalidateSelf() when each Glide tile load finishes.

Because you'll use a special decoder, you'll have to deal with downsampling. Make sure to ask for inSampleSize correctly to prevent loading a 4000x4000 image just to downscale it with a transformation. Use .override to pass the 1000x1000 to the decoder.

Piasy commented 8 years ago

I've just created a big image viewer supporting pan and zoom, with very little memory usage and full featured image loading choices. Powered by Subsampling Scale Image View, Fresco, Glide, and Picasso https://github.com/Piasy/BigImageViewer , hope it helps :)

MFlisar commented 8 years ago

Thanks. But in my use case I saw that ssiv is slow on some devices and PhotoView with something like ion and deep zoom was way faster...

I already tried ssiv and normal glide but was not content with the speed of the view...

Piasy commented 8 years ago

Cool, I'll checkout those libraries