Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OSMDroid Loading Custom Offline tiles From Assets Folder

I was wondering whether it was possible to do such a thing. I know that one would need to modify some of the existing code to pull this off but I was wondering if anyone had any direction on where to look and how to do this.

I am placing a few custom tiles on a specific area on the map as a replacement for OSM tiles providers but need them to be stored in the /assets/ folder. Any ideas?

like image 627
Andrew Grosner Avatar asked Oct 02 '12 15:10

Andrew Grosner


1 Answers

I use the nexts classes to do that.

import java.io.InputStream;

import org.osmdroid.ResourceProxy.string;
import org.osmdroid.tileprovider.util.StreamUtils;

import android.content.res.AssetManager;
import android.graphics.drawable.Drawable;

public class AssetsTileSource extends CustomBitmapTileSourceBase {
        private final AssetManager mAssetManager;

        public AssetsTileSource(final AssetManager assetManager, final String aName, final string aResourceId,
                        final int aZoomMinLevel, final int aZoomMaxLevel, final int aTileSizePixels,
                        final String aImageFilenameEnding) {
                super(aName, aResourceId, aZoomMinLevel, aZoomMaxLevel, aTileSizePixels, aImageFilenameEnding);
                mAssetManager = assetManager;
        }

        @Override
        public Drawable getDrawable(final String aFilePath) {
                InputStream inputStream = null;
                try {
                        inputStream = mAssetManager.open(aFilePath);
                        if (inputStream != null) {
                                final Drawable drawable = getDrawable(inputStream);
                                return drawable;
                        }
                } catch (final Throwable e) {
                        // Tile does not exist in assets folder.
                        // Ignore silently
                } finally {
                        if (inputStream != null) {
                                StreamUtils.closeStream(inputStream);
                        }
                }

                return null;
        }
}

MapTileFileAssetsProvider.java

public class MapTileFileAssetsProvider extends MapTileModuleProviderBase {

            protected ITileSource mTileSource;

            public MapTileFileAssetsProvider(final ITileSource pTileSource) {
                    super(OpenStreetMapTileProviderConstants.NUMBER_OF_TILE_FILESYSTEM_THREADS, OpenStreetMapTileProviderConstants.TILE_FILESYSTEM_MAXIMUM_QUEUE_SIZE);

                    mTileSource = pTileSource;
            }

            @Override
            public boolean getUsesDataConnection() {
                    return false;
            }

            @Override
            protected String getName() {
                    return "Assets Folder Provider";
            }

            @Override
            protected String getThreadGroupName() {
                    return "assetsfolder";
            }

            @Override
            protected Runnable getTileLoader() {
                    return new TileLoader();
            }

            @Override
            public int getMinimumZoomLevel() {
                    return mTileSource != null ? mTileSource.getMinimumZoomLevel() : MAXIMUM_ZOOMLEVEL;
            }

            @Override
            public int getMaximumZoomLevel() {
                    return mTileSource != null ? mTileSource.getMaximumZoomLevel() : MINIMUM_ZOOMLEVEL;
            }

            @Override
            public void setTileSource(final ITileSource pTileSource) {
                    mTileSource = pTileSource;
            }

            private class TileLoader extends MapTileModuleProviderBase.TileLoader {

                    @Override
                    public Drawable loadTile(final MapTileRequestState pState) throws CantContinueException {

                            if (mTileSource == null) {
                                    return null;
                            }

                            final MapTile pTile = pState.getMapTile();
                            String path = mTileSource.getTileRelativeFilenameString(pTile);

                            Drawable drawable;
                            try {
                                    drawable = mTileSource.getDrawable(path);
                            } catch (final LowMemoryException e) {
                                    // low memory so empty the queue
                                    throw new CantContinueException(e);
                            }

                            return drawable;
                    }
            }
    }

And

import java.io.File;
import java.io.InputStream;
import java.util.Random;

import org.osmdroid.ResourceProxy;
import org.osmdroid.ResourceProxy.string;
import org.osmdroid.tileprovider.ExpirableBitmapDrawable;
import org.osmdroid.tileprovider.MapTile;
import org.osmdroid.tileprovider.constants.OpenStreetMapTileProviderConstants;
import org.osmdroid.tileprovider.tilesource.ITileSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;

public abstract class CustomBitmapTileSourceBase implements ITileSource,
                OpenStreetMapTileProviderConstants {

        private static final Logger logger = LoggerFactory.getLogger(CustomBitmapTileSourceBase.class);

        private static int globalOrdinal = 0;

        private final int mMinimumZoomLevel;
        private final int mMaximumZoomLevel;

        private final int mOrdinal;
        protected final String mName;
        protected final String mImageFilenameEnding;
        protected final Random random = new Random();

        private final int mTileSizePixels;

        private final string mResourceId;

        public CustomBitmapTileSourceBase(final String aName, final string aResourceId,
                        final int aZoomMinLevel, final int aZoomMaxLevel, final int aTileSizePixels,
                        final String aImageFilenameEnding) {
                mResourceId = aResourceId;
                mOrdinal = globalOrdinal++;
                mName = aName;
                mMinimumZoomLevel = aZoomMinLevel;
                mMaximumZoomLevel = aZoomMaxLevel;
                mTileSizePixels = aTileSizePixels;
                mImageFilenameEnding = aImageFilenameEnding;
        }

        @Override
        public int ordinal() {
                return mOrdinal;
        }

        @Override
        public String name() {
                return mName;
        }

        public String pathBase() {
                return mName;
        }

        public String imageFilenameEnding() {
                return mImageFilenameEnding;
        }

        @Override
        public int getMinimumZoomLevel() {
                return mMinimumZoomLevel;
        }

        @Override
        public int getMaximumZoomLevel() {
                return mMaximumZoomLevel;
        }

        @Override
        public int getTileSizePixels() {
                return mTileSizePixels;
        }

        @Override
        public String localizedName(final ResourceProxy proxy) {
                return proxy.getString(mResourceId);
        }

        @Override
        public Drawable getDrawable(final String aFilePath) {
                try {
                        // default implementation will load the file as a bitmap and create
                        // a BitmapDrawable from it
                        final Bitmap bitmap = BitmapFactory.decodeFile(aFilePath);
                        if (bitmap != null) {
                                return new ExpirableBitmapDrawable(bitmap);
                        } else {
                                // if we couldn't load it then it's invalid - delete it
                                try {
                                        new File(aFilePath).delete();
                                } catch (final Throwable e) {
                                        logger.error("Error deleting invalid file: " + aFilePath, e);
                                }
                        }
                } catch (final OutOfMemoryError e) {
                        logger.error("OutOfMemoryError loading bitmap: " + aFilePath);
                        System.gc();
                }
                return null;
        }

        @Override
        public String getTileRelativeFilenameString(final MapTile tile) {
                final StringBuilder sb = new StringBuilder();
                sb.append(pathBase());
                sb.append('/');
                sb.append(tile.getX());
                sb.append('_');
                sb.append(tile.getY());
                sb.append('_');
                sb.append(tile.getZoomLevel());
                sb.append(imageFilenameEnding());
                return sb.toString();
        }


        @Override
        public Drawable getDrawable(final InputStream aFileInputStream) {
                try {
                        // default implementation will load the file as a bitmap and create
                        // a BitmapDrawable from it
                        final Bitmap bitmap = BitmapFactory.decodeStream(aFileInputStream);
                        if (bitmap != null) {
                                return new ExpirableBitmapDrawable(bitmap);
                        }
                        System.gc();
                } catch (final OutOfMemoryError e) {
                        logger.error("OutOfMemoryError loading bitmap");
                        System.gc();
                        //throw new LowMemoryException(e);
                }
                return null;
        }

        public final class LowMemoryException extends Exception {
                private static final long serialVersionUID = 146526524087765134L;

                public LowMemoryException(final String pDetailMessage) {
                        super(pDetailMessage);
                }

                public LowMemoryException(final Throwable pThrowable) {
                        super(pThrowable);
                }
        }
}

Modify method getTileRelativeFilenameString() to get yout tiles (i use the next format: x_y_zoom.png)

Example:

mapView = new MapView(getApplicationContext(), 256);
mapView.setClickable(true);
mapView.setTag("Mapa");
mapView.setTileSource(TileSourceFactory.MAPNIK);
mapView.setMultiTouchControls(true);
mapView.setUseDataConnection(true);

MapTileModuleProviderBase moduleProvider = 
    new MapTileFileAssetsProvider(ASSETS_TILE_SOURCE);
SimpleRegisterReceiver simpleReceiver = 
    new SimpleRegisterReceiver(getApplicationContext());
MapTileProviderArray tileProviderArray = 
    new MapTileProviderArray(ASSETS_TILE_SOURCE, simpleReceiver, 
        new MapTileModuleProviderBase[] { moduleProvider });
TilesOverlay tilesOverlay = 
    new TilesOverlay(tileProviderArray, getApplicationContext());

mapView.getOverlays().add(tilesOverlay);
like image 154
jzafrilla Avatar answered Oct 18 '22 14:10

jzafrilla