Я создаю пользовательский UrlTileProvider для Google Maps API, который заботится о разрешении устройства:быстрый способ объединить изображения и преобразовывать их в массив байтов
- если данные плитки 512x512px, просто возвращают плитка
- если данные плитки 256x256px, объединить четыре плитки, соответствующие запрошенной плитки в следующий уровень масштабирования, чтобы вернуть 512x512px плитке
Как TileProvider в GoogleMaps' должен быть подан с Byte [], I необходимо уметь:
- загрузить изображение и преобразовать его в байт [] - OK
- загрузить четыре изображения, объединить их в одно целое, и преобразовать его в байт [] - KO
У меня есть рабочего решения с Android Bitmaps, но слияние + конверсия происходит очень медленно (около 1,5 секунд). Вот код:
public class CustomUrlTileProvider implements TileProvider {
// ---------------------------------------------------------------------------------------
// Private attributes :
private OnlineMapSource _source;
// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
// Constructor :
public CustomUrlTileProvider(OnlineMapSource source) {
this._source = source;
}
@Override
public Tile getTile(int x, int y, int zoom) {
if(_source.getTileSize().getWidth() == 256 && _source.getTileSize().getHeight() == 256) { return getTileFromNextZoomLevel(x, y, zoom); }
else if(_source.getTileSize().getWidth() == 512 && _source.getTileSize().getHeight() == 512) { return getTileFromCurrentZoomLevel(x, y, zoom); }
else return TileProvider.NO_TILE;
}
// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
// Tile creation :
public Tile getTileFromNextZoomLevel(int x, int y, int zoom) {
String topLeftTileUrl = _source.getUrlSchema().replace("{z}", "" + (zoom + 1)).replace("{x}", "" + (x * 2)).replace("{y}", "" + (y * 2));
String topRightTileUrl = _source.getUrlSchema().replace("{z}", "" + (zoom + 1)).replace("{x}", "" + (x * 2 + 1)).replace("{y}", "" + (y * 2));
String bottomLeftTileUrl = _source.getUrlSchema().replace("{z}", "" + (zoom + 1)).replace("{x}", "" + (x * 2)).replace("{y}", "" + (y * 2 + 1));
String bottomRightTileUrl = _source.getUrlSchema().replace("{z}", "" + (zoom + 1)).replace("{x}", "" + (x * 2 + 1)).replace("{y}", "" + (y * 2 + 1));
Bitmap topLeftTile = Utils.getBitmapFromURL(topLeftTileUrl);
Bitmap topRightTile = Utils.getBitmapFromURL(topRightTileUrl);
Bitmap bottomLeftTile = Utils.getBitmapFromURL(bottomLeftTileUrl);
Bitmap bottomRightTile = Utils.getBitmapFromURL(bottomRightTileUrl);
Bitmap[] parts = {
topLeftTile,
topRightTile,
bottomLeftTile,
bottomRightTile
};
Bitmap tileBitmap = Bitmap.createBitmap(parts[0].getWidth() * 2, parts[0].getHeight() * 2, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(tileBitmap);
Paint paint = new Paint();
for (int i = 0; i < parts.length; i++) {
canvas.drawBitmap(parts[i], parts[i].getWidth() * (i % 2), parts[i].getHeight() * (i/2), paint);
}
ByteArrayOutputStream stream = new ByteArrayOutputStream();
tileBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] tile = stream.toByteArray();
return tile == null ? TileProvider.NO_TILE : new Tile(_source.getTileSize().getWidth(), _source.getTileSize().getHeight(), tile);
}
public Tile getTileFromCurrentZoomLevel(int x, int y, int zoom) {
String tileUrl = _source.getUrlSchema().replace("{z}", "" + zoom).replace("{x}", "" + x).replace("{y}", "" + y);
byte[] tile = Utils.getByteArrayFromURL(tileUrl);
return tile == null ? TileProvider.NO_TILE : new Tile(_source.getTileSize().getWidth(), _source.getTileSize().getHeight(), tile);
}
// ---------------------------------------------------------------------------------------
}
Методы Utils.getBitmapFromURL и Utils.getByteArrayFromURL:
public static Bitmap getBitmapFromURL(String src) {
try {
URL url = new URL(src);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
}
catch (IOException e) { return null; }
}
public static byte[] getByteArrayFromURL(String src) {
ByteArrayOutputStream bais = new ByteArrayOutputStream();
InputStream is = null;
try {
is = new URL(src).openStream();
byte[] byteChunk = new byte[4096];
int n;
while ((n = is.read(byteChunk)) > 0) {
bais.write(byteChunk, 0, n);
}
}
catch (IOException e) { e.printStackTrace(); }
finally {
if (is != null) {
try { is.close(); }
catch (IOException e) { e.printStackTrace(); }
}
}
return bais.toByteArray();
}
Так что вопрос: есть ли более быстрый способ достижения второй операции (скачать 4 изображения -> объединить их -> преобразовать результат в байт [])? Чтобы упростить, существует ли способ объединить четыре байта [] (представляющие изображения) в один?
EDIT: Я нашел, что время занимает не слияние, а преобразование Bitmap -> byte []. Поэтому я знаю, что пытаюсь использовать Bitmap.copyPixelsToBuffer вместо Bitmap.compress, без каких-либо успехов (без исключения, но без изображения). Есть идеи ?
Благодаря
К сожалению, прошедшее время, которое я дал, является временем слияния + конвертирования. Время загрузки составляет около 300 мс, а слияние + конвертировать около 1,5 с. У меня есть лучшее решение для первой операции в чистой Java, я буду обновлять исходный пост. –